Paths

Copy Paste Here the path to your Drug-Assay-Study folder

my_path<-"/Users/jonasamar/Desktop/Drug-Assay-Study"
setwd(paste0(my_path,"/Rscripts"))
OOL_path=paste0(my_path,"/Onset of Labor csv")
drug_assay_path=paste0(my_path,"/Drug assay csv")

Libraries

```r
library(tidyverse)
library(tidyselect)
library(reshape2)
library(dplyr)
library(pheatmap)
library(RColorBrewer)
library(viridis)
library(paletteer)
library(tidyr)
library(janitor)
library(lme4)
library(lmerTest)
library(utils)
library(ggplot2)
library(r2glmm)
library(sjstats)
library(gridExtra)

<!-- rnb-source-end -->

<!-- rnb-chunk-end -->


<!-- rnb-text-begin -->


## Loading Data and Models

**OOL data and models**


<!-- rnb-text-end -->


<!-- rnb-chunk-begin -->


<!-- rnb-source-begin eyJkYXRhIjoiYGBgclxuYGBgclxuIyBkZl9tb2RlbFxubG9hZChwYXN0ZTAoT09MX3BhdGgsIFxcL3Blbl9tb2RlbF9jdXJ2ZXNfY3l0b2YucmRhXFwpKVxuIyBjdXJ2ZS5jbGFzc2lmaWNhdGlvbiA8LSBkZl9zdW1cbmN1cnZlLmNsYXNzaWZpY2F0aW9uIDwtIHJlYWQuY3N2KHBhc3RlMChPT0xfcGF0aCwgXFwvcGVuX2NsYXNzaWZpY2F0aW9uX2N1cnZlc19jeXRvZi5jc3ZcXCkpXG4jIHBlbmFsaXplZCBkYXRhc2V0IHdpdGggb3V0Y29tZXMgKERPUykgYW50ZSBwYXJ0dW1cbk9PTF9kYXRhIDwtIHJlYWQuY3N2KHBhc3RlMChPT0xfcGF0aCwgXFwvaW1tdW5vbWVfbm9FR0FfRE9TX3Blbl9PT0wuY3N2XFwpKSAlPiUgICBcbiAgICAgICAgICAgIGZpbHRlcihET1MgPD0gMCkgIyB3ZSBvbmx5IGFyZSBpbnRlcmVzdGVkIGluIERPUyA8PTBcbiMgb3V0Y29tZXNcbkRPUyA8LSBPT0xfZGF0YSRET1NcbiMgcmVzdWx0cyBmcm9tIHVuaXZhcmlhdGUgYW5hbHlzaXMgb24gT09MIGRhdGFcbnNwZWFybWFuX2NvciA8LSByZWFkX2NzdihwYXN0ZTAoT09MX3BhdGgsIFxcL1VuaXZhcmlhdGUgcmVnYXRlZCBPT0wvU3BlYXJtYW5Db3JyZWxhdGlvbnNQdmFsLmNzdlxcKSlcbmBgYFxuYGBgIn0= -->

```r
```r
# df_model
load(paste0(OOL_path, \/pen_model_curves_cytof.rda\))
# curve.classification <- df_sum
curve.classification <- read.csv(paste0(OOL_path, \/pen_classification_curves_cytof.csv\))
# penalized dataset with outcomes (DOS) ante partum
OOL_data <- read.csv(paste0(OOL_path, \/immunome_noEGA_DOS_pen_OOL.csv\)) %>%   
            filter(DOS <= 0) # we only are interested in DOS <=0
# outcomes
DOS <- OOL_data$DOS
# results from univariate analysis on OOL data
spearman_cor <- read_csv(paste0(OOL_path, \/Univariate regated OOL/SpearmanCorrelationsPval.csv\))

<!-- rnb-source-end -->

<!-- rnb-output-begin eyJkYXRhIjoiTmV3IG5hbWVzOlJvd3M6IDc2OCBDb2x1bW5zOiAz4pSA4pSAIENvbHVtbiBzcGVjaWZpY2F0aW9uIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgFxuRGVsaW1pdGVyOiBcXFxuIn0= -->

New names:Rows: 768 Columns: 3── Column specification ─────────────────────────────────────────────────────────────────────────────────────────────────────────────────── Delimiter:




<!-- rnb-output-end -->

<!-- rnb-source-begin eyJkYXRhIjoiYGBgclxuYGBgclxuIyBmZWF0dXJlLmluZGV4XG5sb2FkKHBhc3RlMChPT0xfcGF0aCwgXFwvZmVhdHVyZV9pbmRleC5yZGFcXCkpXG5gYGBcbmBgYCJ9 -->

```r
```r
# feature.index
load(paste0(OOL_path, \/feature_index.rda\))

<!-- rnb-source-end -->

<!-- rnb-chunk-end -->


<!-- rnb-text-begin -->


**Drug Assay data and models**


<!-- rnb-text-end -->


<!-- rnb-chunk-begin -->


<!-- rnb-source-begin eyJkYXRhIjoiYGBgclxuYGBgclxuIyBtb2RlbC5zY29yZXNcbmxvYWQocGFzdGUwKGRydWdfYXNzYXlfcGF0aCwgXFwvbW9kZWwgc2NvcmVzLnJkYVxcKSlcbiMgcHNldWRvX2xvZzEwLmluZGl2aWR1YWwubGluZWFyLm1vZGVsXG5sb2FkKHBhc3RlMChkcnVnX2Fzc2F5X3BhdGgsIFxcL3BzZXVkb19sb2cxMCBtZWRpYW4gbGluZWFyIG1vZGVscy5yZGFcXCkpXG4jIHBzZXVkb19sb2cxMC5tZWRpYW4ubGluZWFyLm1vZGVsXG5sb2FkKHBhc3RlMChkcnVnX2Fzc2F5X3BhdGgsIFxcL3BzZXVkb19sb2cxMCBpbmRpdmlkdWFsIGxpbmVhciBtb2RlbHMucmRhXFwpKVxuIyBNZWRpYW5Eb3NlcmVwb25zZVxubG9hZChwYXN0ZTAoZHJ1Z19hc3NheV9wYXRoLCBcXC9tZWRpYW4gcGVuIGRvc2UgcmVzcG9uc2Ugd2l0aCBzY2FsZXMucmRhXFwpKVxuIyBBbGxQZW5Eb3NlcmVwb25zZVxubG9hZChwYXN0ZTAoZHJ1Z19hc3NheV9wYXRoLCBcXC9hbGwgcGVuIGRvc2UgcmVzcG9uc2Ugd2l0aCBzY2FsZXMucmRhXFwpKVxuYGBgXG5gYGAifQ== -->

```r
```r
# model.scores
load(paste0(drug_assay_path, \/model scores.rda\))
# pseudo_log10.individual.linear.model
load(paste0(drug_assay_path, \/pseudo_log10 median linear models.rda\))
# pseudo_log10.median.linear.model
load(paste0(drug_assay_path, \/pseudo_log10 individual linear models.rda\))
# MedianDosereponse
load(paste0(drug_assay_path, \/median pen dose response with scales.rda\))
# AllPenDosereponse
load(paste0(drug_assay_path, \/all pen dose response with scales.rda\))

<!-- rnb-source-end -->

<!-- rnb-chunk-end -->


<!-- rnb-text-begin -->


## Scores

Here we want to compare the drug effect on each feature to the "normal" behavior of the feature modeled in OOL study.

### Auxiliaries score functions

**drug.effect**


<!-- rnb-text-end -->


<!-- rnb-chunk-begin -->


<!-- rnb-source-begin eyJkYXRhIjoiYGBgclxuYGBgclxuIyBGdW5jdGlvbiB3aGljaCByZXR1cm46XG4jICsxIGZvciBhY3RpdmF0aW5nIGRydWdzXG4jIC0xIGZvciBpbmhpYml0aW5nIGRydWdzXG4jIDAgZm9yIG5vbiBhY3RpdmUgKG9yIHVuY2VydGFpbikgZHJ1Z3NcbiMgYmFzZWQgb24gdGhlIHNsb3BlIG9mIHRoZSBtb2RlbCBhbmQgaXRzIHAtdmFsdWVcblxuZHJ1Zy5lZmZlY3QgPC0gZnVuY3Rpb24oc2xvcGUsIHB2YWwsIHNsb3BlLnRocmVzaG9sZCwgcHZhbC50aHJlc2hvbGQpe1xuICBpZiAoKGFicyhzbG9wZSkgPiBzbG9wZS50aHJlc2hvbGQpICYgKHB2YWwgPCBwdmFsLnRocmVzaG9sZCkgJiAoIWlzLm5hKHNsb3BlKSkgJiAoIWlzLm5hKHB2YWwpKSl7XG4gICAgcmV0dXJuKHNsb3BlL2FicyhzbG9wZSkpXG4gIH1cbiAgZWxzZXtcbiAgICByZXR1cm4oMClcbiAgfVxufVxuYGBgXG5gYGAifQ== -->

```r
```r
# Function which return:
# +1 for activating drugs
# -1 for inhibiting drugs
# 0 for non active (or uncertain) drugs
# based on the slope of the model and its p-value

drug.effect <- function(slope, pval, slope.threshold, pval.threshold){
  if ((abs(slope) > slope.threshold) & (pval < pval.threshold) & (!is.na(slope)) & (!is.na(pval))){
    return(slope/abs(slope))
  }
  else{
    return(0)
  }
}

<!-- rnb-source-end -->

<!-- rnb-chunk-end -->


<!-- rnb-text-begin -->


**feature.normal.behavior.at.TTL**


<!-- rnb-text-end -->


<!-- rnb-chunk-begin -->


<!-- rnb-source-begin eyJkYXRhIjoiYGBgclxuYGBgclxuIyBGdW5jdGlvbiB3aGljaCByZXR1cm5zXG4jIDEgaWYgdGhlIG1vZGVsIChvZiB0aGUgT09MIGZlYXR1cmUpIGlzIGluY3JlYXNpbmcgYXQgVFRMXG4jIC0xIGlmIHRoZSBtb2RlbCAob2YgdGhlIE9PTCBmZWF0dXJlKSBpcyBkZWNyZWFzaW5nIGF0IFRUTFxuIyBOQSBpZiB0aGUgYmVoYXZpb3Igb2YgdGhlIGZlYXR1cmUgaXMgaW5jb25jbHVzaXZlIChtaXNzaW5nIG1vZGVsIG9yIHRvbyB3ZWFrIHNsb3BlKVxuIyBiYXNlZCBvbiB0aGUgbW9kZWwgKGNvbnRhaW5lZCBpbiBhIGxpc3QpIGl0c2VsZiBhbmQgaXRzIHAtdmFsdWVcblxuZmVhdHVyZS5ub3JtYWwuYmVoYXZpb3IuYXQuVFRMIDwtIGZ1bmN0aW9uKG1vZGVsLCBwdmFsLCBzbG9wZS50aHJlc2hvbGQsIHB2YWwudGhyZXNob2xkLCBUVEwpe1xuICBpZiAobGVuZ3RoKHB2YWwpID09IDAgfHwgaXMubmEocHZhbCkgfHxwdmFsID4gcHZhbC50aHJlc2hvbGQgfHwgbGVuZ3RoKG1vZGVsKSA9PSAwKXtcbiAgICByZXR1cm4oTkEpXG4gIH1cbiAgZWxzZXtcbiAgICAjIEhlcmUgd2UgZm9jdXMgdW4gdGhlIGRlcml2YXRpdmUgYXJvdW5kIDAgdG8gZXN0aW1hdGUgdGhlIGJlaGF2aW9yIG9mIHRoZSBmZWF0dXJlXG4gICAgbW9kZWwgPC0gbW9kZWxbWzFdXVxuICAgIHF1YWRyYXRpYyA8LSAobGVuZ3RoKG1vZGVsKSA9PSAzKVxuXG4gICAgIyBEZXJpdmF0aXZlIG9mIHRoZSBtb2RlbCBhdCBUVExcbiAgICAjIGZvciBxdWFkcmF0aWMgbW9kZWxcbiAgICBpZiAocXVhZHJhdGljKXtcbiAgICAgIGRlcml2IDwtIDIqbW9kZWxbWydET1MyJ11dKlRUTCArIG1vZGVsW1snRE9TJ11dXG4gICAgfSBcbiAgICAjIGZvciBsaW5lYXIgbW9kZWxcbiAgICBlbHNle1xuICAgICAgZGVyaXYgPC0gbW9kZWxbWydET1MnXV1cbiAgICB9XG4gICAgXG4gICAgIyBSZXR1cm5pbmcgZWZmZWN0IGNvZWZmaWNpZW50XG4gICAgaWYgKGFicyhkZXJpdikgPiBzbG9wZS50aHJlc2hvbGQpe1xuICAgICAgcmV0dXJuKGRlcml2L2FicyhkZXJpdikpXG4gICAgfVxuICAgIGVsc2V7XG4gICAgICByZXR1cm4oTkEpXG4gICAgfVxuICB9XG59XG5gYGBcbmBgYCJ9 -->

```r
```r
# Function which returns
# 1 if the model (of the OOL feature) is increasing at TTL
# -1 if the model (of the OOL feature) is decreasing at TTL
# NA if the behavior of the feature is inconclusive (missing model or too weak slope)
# based on the model (contained in a list) itself and its p-value

feature.normal.behavior.at.TTL <- function(model, pval, slope.threshold, pval.threshold, TTL){
  if (length(pval) == 0 || is.na(pval) ||pval > pval.threshold || length(model) == 0){
    return(NA)
  }
  else{
    # Here we focus un the derivative around 0 to estimate the behavior of the feature
    model <- model[[1]]
    quadratic <- (length(model) == 3)

    # Derivative of the model at TTL
    # for quadratic model
    if (quadratic){
      deriv <- 2*model[['DOS2']]*TTL + model[['DOS']]
    } 
    # for linear model
    else{
      deriv <- model[['DOS']]
    }
    
    # Returning effect coefficient
    if (abs(deriv) > slope.threshold){
      return(deriv/abs(deriv))
    }
    else{
      return(NA)
    }
  }
}

<!-- rnb-source-end -->

<!-- rnb-chunk-end -->


<!-- rnb-text-begin -->


**create.drug.effect.data.frame**


<!-- rnb-text-end -->


<!-- rnb-chunk-begin -->


<!-- rnb-source-begin eyJkYXRhIjoiYGBgclxuYGBgclxuIyBGdW5jdGlvbiB3aGljaCBjcmVhdGVzIGEgZGF0YWZyYW1lIHdpdGggXG4jIDEgd2hlbiB0aGUgZHJ1ZyBpcyBhZmZlY3RpbmcgdGhlIGZlYXR1cmUgdGhlIG9wcG9zaXRlIGRpcmVjdGlvbiBvZiBpdHMgbm9ybWFsIGJlaGF2aW9yIGF0IFRUTFxuIyAtMSB3aGVuIHRoZSBkcnVnIGlzIGFmZmVjdGluZyB0aGUgZmVhdHVyZSB0aGUgc2FtZSBkaXJlY3Rpb24gb2YgaXRzIG5vcm1hbCBiZWhhdmlvciBhdCBUVExcbiMgMCB3aGVuIHRoZSBlZmZlY3Qgb2YgdGhlIGRydWcgaXMgbnVsbFxuIyBOQSB3aGVuIGJlaGF2aW9yIG9mIHRoZSBmZWF0dXJlIGlzIG51bGwgb3IgaGFyZCB0byBlc3RpbWF0ZSAoaGlnaCBwLXZhbHVlKSBvciBpZiB3ZSBtaXNzIGRhdGEgaW4gdGhlIGRydWcgYXNzYXkgc3R1ZHlcblxuY3JlYXRlLmRydWcuZWZmZWN0LmRhdGEuZnJhbWUgPC0gZnVuY3Rpb24oZHJ1Zy5uYW1lLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbm9ybWFsLmJlaGF2aW9yLnB2YWwudGhyZXNob2xkLCBcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5vcm1hbC5iZWhhdmlvci5zbG9wZS50aHJlc2hvbGQsIFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZHJ1Zy5wdmFsLnRocmVzaG9sZCwgXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkcnVnLnNsb3BlLnRocmVzaG9sZCxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRUTCxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZlYXR1cmVzLm9mLmludGVyZXN0KXtcbiAgXG4gICMgRGF0YWZyYW1lIGZlYXR1cmUgfiBzdGltdWxhdGlvbiBjb250YWluaW5nIHRoZSBmaW5hbCBlZmZlY3Qgb24gYSBkcnVnIG9uIGVhY2ggZmVhdHVyZSB1bmRlciBlYWNoIHN0aW11bGF0aW9uXG4gIGRydWcuZWZmZWN0LmRhdGFmcmFtZSA8LSBtb2RlbC5zY29yZXMgJT4lXG4gICAgICAgICAgICAgICAgICAgICAgICBmaWx0ZXIoZHJ1ZyA9PSBkcnVnLm5hbWUpICU+JVxuICAgICAgICAgICAgICAgICAgICAgICAgcm93d2lzZSgpICU+JVxuICAgICAgICAgICAgICAgICAgICAgICAgbXV0YXRlKGRydWcuYmVoYXZpb3IgPSBkcnVnLmVmZmVjdChzbG9wZSwgXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwdmFsLCBcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNsb3BlLnRocmVzaG9sZCA9IGRydWcuc2xvcGUudGhyZXNob2xkLCBcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHB2YWwudGhyZXNob2xkID0gZHJ1Zy5wdmFsLnRocmVzaG9sZCksXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcG9wdWxhdGlvbiA9IHN0cl9leHRyYWN0KGZlYXR1cmUsIFxcXlteX10rXFwpLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlYWdlbnRfc3RpbSA9IHN0cl9leHRyYWN0KGZlYXR1cmUsIFxcKD88PV8pLiokXFwpKSAlPiVcbiAgICAgICAgICAgICAgICAgICAgICAgIHNlbGVjdChwb3B1bGF0aW9uLCBkcnVnLmJlaGF2aW9yLCByZWFnZW50X3N0aW0pICU+JVxuICAgICAgICAgICAgICAgICAgICAgICAgcGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9IHJlYWdlbnRfc3RpbSwgdmFsdWVzX2Zyb20gPSBkcnVnLmJlaGF2aW9yKVxuICBcbiAgIyBDb25jYXRlbmF0aW9uIG9mIGFsbCBpbmZvcm1hdGlvbiBvbiB0aGUgZmVhdHVyZSBtb2RlbHMgKyBub3JtYWwuYmVoYXZpb3IgPSArMSwgLTEgb3IgTkFcbiAgbW9kZWwuaW5mbyA8LSBtZXJnZShkZl9tb2RlbHMsIGN1cnZlLmNsYXNzaWZpY2F0aW9uLCBieS54ID0gXFxmZWF0dXJlXFwsIGJ5LnkgPSBcXGN5dG9mXFwpICU+JVxuICAgICAgICAgICAgICAgIHJvd3dpc2UoKSAlPiVcbiAgICAgICAgICAgICAgICBtdXRhdGUobm9ybWFsLmJlaGF2aW9yID0gZmVhdHVyZS5ub3JtYWwuYmVoYXZpb3IuYXQuVFRMKG1vZGVsLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcHZhbCwgXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBub3JtYWwuYmVoYXZpb3Iuc2xvcGUudGhyZXNob2xkLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbm9ybWFsLmJlaGF2aW9yLnB2YWwudGhyZXNob2xkLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgVFRMKSxcbiAgICAgICAgICAgICAgICAgICAgICAgIyBBZGRpbmcgc29tZSBudWFuY2UgdG8gdGhlIGltcG9ydGFuY2Ugb2YgdGhlIGJlaGF2aW9yXG4gICAgICAgICAgICAgICAgICAgICAgIG5vcm1hbC5iZWhhdmlvciA9IGlmZWxzZShmZWF0dXJlICVpbiUgZmVhdHVyZXMub2YuaW50ZXJlc3QsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBub3JtYWwuYmVoYXZpb3IsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBub3JtYWwuYmVoYXZpb3IvMikpXG5cbiAgIyBEYXRhZnJhbWUgZmVhdHVyZSB+IHN0aW11bGF0aW9uIGNvbnRhaW5pbmcgdGhlIHZhbHVlcyBvZiBub3JtYWwuYmVoYXZpb3JcbiAgYmVoYXZpb3IuZGF0YWZyYW1lIDwtIG1vZGVsLmluZm8gJT4lXG4gICAgICAgICAgICAgICAgICAgICAgICAgIG11dGF0ZShwb3B1bGF0aW9uID0gc3RyX2V4dHJhY3QoZmVhdHVyZSwgXFxeW15fXStcXCksXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZWFnZW50X3N0aW0gPSBzdHJfZXh0cmFjdChmZWF0dXJlLCBcXCg/PD1fKS4qJFxcKSkgJT4lXG4gICAgICAgICAgICAgICAgICAgICAgICAgIHNlbGVjdChwb3B1bGF0aW9uLCBub3JtYWwuYmVoYXZpb3IsIHJlYWdlbnRfc3RpbSkgJT4lXG4gICAgICAgICAgICAgICAgICAgICAgICAgIHBpdm90X3dpZGVyKG5hbWVzX2Zyb20gPSByZWFnZW50X3N0aW0sIHZhbHVlc19mcm9tID0gbm9ybWFsLmJlaGF2aW9yKSAlPiVcbiAgICAgICAgICAgICAgICAgICAgICAgICAgIyByZW1vdmluZyBmZWF0dXJlcyBub3QgbWVhc3VyZWQgaW4gYm90aCBzdHVkaWVzIChkcnVncyBhbmQgT09MKVxuICAgICAgICAgICAgICAgICAgICAgICAgICAjIGBTVEFUM19MUFNgLCBgU1RBVDVfTFBTYCwgYFNUQVQxX0xQU2AsIGBTVEFUNl9MUFNgLCBgU1RBVDFfR01DU0ZgXG4gICAgICAgICAgICAgICAgICAgICAgICAgICMgXFxTVEFUMV91bnN0aW1cXFxuICAgICAgICAgICAgICAgICAgICAgICAgICBmaWx0ZXIocG9wdWxhdGlvbiAlaW4lIGRydWcuZWZmZWN0LmRhdGFmcmFtZSRwb3B1bGF0aW9uKSAlPiVcbiAgICAgICAgICAgICAgICAgICAgICAgICAgc2VsZWN0KG9uZV9vZihjb2xuYW1lcyhkcnVnLmVmZmVjdC5kYXRhZnJhbWUpKSlcbiAgICAgICAgICAgICAgICAgICAgICAgIFxuICAjIERhdGFmcmFtZSBmZWF0dXJlIH4gc3RpbXVsYXRpb24gY29udGFpbmluZyB0aGUgcHJvZHVjdCBvZiBiZWhhdmlvci5tYXRyaXggYW5kIGRydWcuZWZmZWN0Lm1hdHJpeFxuICBkcnVnLmZpbmFsLmVmZmVjdC5kYXRhZnJhbWU8LSBtZXJnZShwaXZvdF9sb25nZXIoc2VsZWN0KGJlaGF2aW9yLmRhdGFmcmFtZSwgXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG9uZV9vZihjb2xuYW1lcyhkcnVnLmVmZmVjdC5kYXRhZnJhbWUpKSksIFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29scyA9IC1wb3B1bGF0aW9uLCBcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5hbWVzX3RvID0gXFxyZWFnZW50X3N0aW1cXCwgXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2YWx1ZXNfdG8gPSBcXG5vcm1hbC5iZWhhdmlvclxcKSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGl2b3RfbG9uZ2VyKHNlbGVjdChkcnVnLmVmZmVjdC5kYXRhZnJhbWUsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgb25lX29mKGNvbG5hbWVzKGJlaGF2aW9yLmRhdGFmcmFtZSkpKSwgXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xzID0gLXBvcHVsYXRpb24sIFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbmFtZXNfdG8gPSBcXHJlYWdlbnRfc3RpbVxcLCBcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZhbHVlc190byA9IFxcZHJ1Zy5iZWhhdmlvclxcKSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYnkgPSBjKFxccG9wdWxhdGlvblxcLCBcXHJlYWdlbnRfc3RpbVxcKSkgJT4lXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJvd3dpc2UoKSAlPiVcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbXV0YXRlKGRydWcuZmluYWwuZWZmZWN0ID0gaWZlbHNlKGlzLm5hKG5vcm1hbC5iZWhhdmlvcikgfHxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaXMubmEoZHJ1Zy5iZWhhdmlvciksXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBOQSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC1ub3JtYWwuYmVoYXZpb3IqZHJ1Zy5iZWhhdmlvcikpICU+JVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZWxlY3QocG9wdWxhdGlvbiwgcmVhZ2VudF9zdGltLCBkcnVnLmZpbmFsLmVmZmVjdCkgJT4lXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBpdm90X3dpZGVyKG5hbWVzX2Zyb20gPSByZWFnZW50X3N0aW0sIHZhbHVlc19mcm9tID0gZHJ1Zy5maW5hbC5lZmZlY3QpXG5cbiAgcmV0dXJuKGRydWcuZmluYWwuZWZmZWN0LmRhdGFmcmFtZSlcbn1cbmBgYFxuYGBgIn0= -->

```r
```r
# Function which creates a dataframe with 
# 1 when the drug is affecting the feature the opposite direction of its normal behavior at TTL
# -1 when the drug is affecting the feature the same direction of its normal behavior at TTL
# 0 when the effect of the drug is null
# NA when behavior of the feature is null or hard to estimate (high p-value) or if we miss data in the drug assay study

create.drug.effect.data.frame <- function(drug.name,
                                          normal.behavior.pval.threshold, 
                                          normal.behavior.slope.threshold, 
                                          drug.pval.threshold, 
                                          drug.slope.threshold,
                                          TTL,
                                          features.of.interest){
  
  # Dataframe feature ~ stimulation containing the final effect on a drug on each feature under each stimulation
  drug.effect.dataframe <- model.scores %>%
                        filter(drug == drug.name) %>%
                        rowwise() %>%
                        mutate(drug.behavior = drug.effect(slope, 
                                                            pval, 
                                                            slope.threshold = drug.slope.threshold, 
                                                            pval.threshold = drug.pval.threshold),
                               population = str_extract(feature, \^[^_]+\),
                               reagent_stim = str_extract(feature, \(?<=_).*$\)) %>%
                        select(population, drug.behavior, reagent_stim) %>%
                        pivot_wider(names_from = reagent_stim, values_from = drug.behavior)
  
  # Concatenation of all information on the feature models + normal.behavior = +1, -1 or NA
  model.info <- merge(df_models, curve.classification, by.x = \feature\, by.y = \cytof\) %>%
                rowwise() %>%
                mutate(normal.behavior = feature.normal.behavior.at.TTL(model,
                                                                        pval, 
                                                                        normal.behavior.slope.threshold,
                                                                        normal.behavior.pval.threshold,
                                                                        TTL),
                       # Adding some nuance to the importance of the behavior
                       normal.behavior = ifelse(feature %in% features.of.interest,
                                                normal.behavior,
                                                normal.behavior/2))

  # Dataframe feature ~ stimulation containing the values of normal.behavior
  behavior.dataframe <- model.info %>%
                          mutate(population = str_extract(feature, \^[^_]+\),
                                 reagent_stim = str_extract(feature, \(?<=_).*$\)) %>%
                          select(population, normal.behavior, reagent_stim) %>%
                          pivot_wider(names_from = reagent_stim, values_from = normal.behavior) %>%
                          # removing features not measured in both studies (drugs and OOL)
                          # `STAT3_LPS`, `STAT5_LPS`, `STAT1_LPS`, `STAT6_LPS`, `STAT1_GMCSF`
                          # \STAT1_unstim\
                          filter(population %in% drug.effect.dataframe$population) %>%
                          select(one_of(colnames(drug.effect.dataframe)))
                        
  # Dataframe feature ~ stimulation containing the product of behavior.matrix and drug.effect.matrix
  drug.final.effect.dataframe<- merge(pivot_longer(select(behavior.dataframe, 
                                                           one_of(colnames(drug.effect.dataframe))), 
                                                   cols = -population, 
                                                   names_to = \reagent_stim\, 
                                                   values_to = \normal.behavior\),
                                      pivot_longer(select(drug.effect.dataframe,
                                                          one_of(colnames(behavior.dataframe))), 
                                                   cols = -population, 
                                                   names_to = \reagent_stim\, 
                                                   values_to = \drug.behavior\),
                                      by = c(\population\, \reagent_stim\)) %>%
                                rowwise() %>%
                                mutate(drug.final.effect = ifelse(is.na(normal.behavior) ||
                                                                    is.na(drug.behavior),
                                                                  NA,
                                                                  -normal.behavior*drug.behavior)) %>%
                                select(population, reagent_stim, drug.final.effect) %>%
                                pivot_wider(names_from = reagent_stim, values_from = drug.final.effect)

  return(drug.final.effect.dataframe)
}

<!-- rnb-source-end -->

<!-- rnb-chunk-end -->


<!-- rnb-text-begin -->


### Features of interest

For now, we don't have a ML model with selected features helping us discriminate which features are more important to look at so we are looking at two sets of features :
- the top 15 Cytof features from the OOL paper
- the features from the univariate analysis with an absolute Spearman score > 0.3

**Top 15 features from OOL paper**


<!-- rnb-text-end -->


<!-- rnb-chunk-begin -->


<!-- rnb-source-begin eyJkYXRhIjoiYGBgclxuYGBgclxuIyBUb3AgaW1tdW5vbWUgZmVhdHVyZXMgZnJvbSB0aGUgT09MIHN0dWR5XG4jIHdlIGFzc29jaWF0ZSBhIGNvZWZmICsxIChpbmNyZWFzaW5nKSBvciAtMSAoZGVjcmVhc2luZykgdG8gdGhlIGZlYXR1cmVzXG5PT0wudG9wLmltbXVub21lLmZlYXR1cmVzIDwtIGxpc3QoXFxDRDU2bG9DRDE2cG9zTktfU1RBVDFfSUZOYVxcPTEsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBHcmFudWxvY3l0ZXMgbWlzc2luZyBpbiB0aGUgZHJ1ZyBhc3NheSBzdHVkeVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFxcQ0Q1NmhpQ0QxNm5lZ05LX1NUQVQxX0lGTmFcXD0xLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFxcQ0Q0VG5haXZlX01BUEtBUEsyX0lGTmFcXD0xLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFxcbmNNQ3NfQ1JFQl9HTUNTRlxcPS0xLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFxcQ0Q4VGNtX01BUEtBUEsyX3Vuc3RpbVxcPTEsICMtMSBhdCBUVEwgPSAwXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgXFxDRDhUZW1fTUFQS0FQSzJfdW5zdGltXFw9MSwgIy0xIGF0IFRUTCA9IDBcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBcXHBEQ3NfU1RBVDFfSUZOYVxcPTEsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgXFxCY2VsbHNfTUFQS0FQSzJfTFBTXFw9MSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBcXENENFRlbV9NQVBLQVBLMl91bnN0aW1cXD0xLCAjLTEgYXQgVFRMID0gMFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFxcQ0Q4VGNtX01BUEtBUEsyX0lGTmFcXD0xLCBcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBcXENEOFRlbV9NQVBLQVBLMl9JRk5hXFw9MSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIEJjZWxscyBtaXNzaW5nIGluIHRoZSBkcnVnIGFzc2F5IHN0dWR5XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgXFxDRDRUZW1fTkZrQl9JTDI0NlxcPS0xLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFxcQ0Q0VGNtX0lrQl91bnN0aW1cXD0xLCAjLTEgYXQgVFRMID0gMFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFxcbURDc19TVEFUNl9JRk5hXFw9MSwgIy0xIGF0IFRUTCA9IDBcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBcXHBEQ3NfU1RBVDZfSUZOYVxcPTEsICMtMSBhdCBUVEwgPSAwXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgXFxtRENzX01BUEtBUEsyX3Vuc3RpbVxcPS0xLCBcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBcXHBEQ3NfTUFQS0FQSzJfdW5zdGltXFw9LTFcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApXG5gYGBcbmBgYCJ9 -->

```r
```r
# Top immunome features from the OOL study
# we associate a coeff +1 (increasing) or -1 (decreasing) to the features
OOL.top.immunome.features <- list(\CD56loCD16posNK_STAT1_IFNa\=1,
                                  # Granulocytes missing in the drug assay study
                                  \CD56hiCD16negNK_STAT1_IFNa\=1,
                                  \CD4Tnaive_MAPKAPK2_IFNa\=1,
                                  \ncMCs_CREB_GMCSF\=-1,
                                  \CD8Tcm_MAPKAPK2_unstim\=1, #-1 at TTL = 0
                                  \CD8Tem_MAPKAPK2_unstim\=1, #-1 at TTL = 0
                                  \pDCs_STAT1_IFNa\=1,
                                  \Bcells_MAPKAPK2_LPS\=1,
                                  \CD4Tem_MAPKAPK2_unstim\=1, #-1 at TTL = 0
                                  \CD8Tcm_MAPKAPK2_IFNa\=1, 
                                  \CD8Tem_MAPKAPK2_IFNa\=1,
                                  # Bcells missing in the drug assay study
                                  \CD4Tem_NFkB_IL246\=-1,
                                  \CD4Tcm_IkB_unstim\=1, #-1 at TTL = 0
                                  \mDCs_STAT6_IFNa\=1, #-1 at TTL = 0
                                  \pDCs_STAT6_IFNa\=1, #-1 at TTL = 0
                                  \mDCs_MAPKAPK2_unstim\=-1, 
                                  \pDCs_MAPKAPK2_unstim\=-1
                                  )

<!-- rnb-source-end -->

<!-- rnb-chunk-end -->


<!-- rnb-text-begin -->


**Top features from the univariate analysis**


<!-- rnb-text-end -->


<!-- rnb-chunk-begin -->


<!-- rnb-source-begin eyJkYXRhIjoiYGBgclxuYGBgclxuIyBUb3AgaW1tdW5vbWUgZmVhdHVyZXMgZnJvbSB0aGUgdW5pdmFyaWF0ZSBhbmFseXNpcyBvbiBPT0wgZGF0YVxuIyB3ZSBhc3NvY2lhdGUgYSBjb2VmZiArMSAoaW5jcmVhc2luZykgb3IgLTEgKGRlY3JlYXNpbmcpIHRvIHRoZSBmZWF0dXJlc1xuXG51bml2YXJpYXRlLk9PTC5mZWF0dXJlcyA8LSBhcHBseShzcGVhcm1hbl9jb3JbYWJzKHNwZWFybWFuX2NvciRgU3BlYXJtYW4gY29ycmApID4gMC4zLF0sICMgdGFraW5nIGZlYXR1cmVzIHdpdGggfFNwZWFybWFucnwgPiAwLjNcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDEsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmdW5jdGlvbihyb3cpeyAjIGFzc29jaWF0aW5nIHRoZSBmZWF0dXJlIG5hbWUgdG8gKzEgKGluY3JlYXNpbmcpIG9yIC0xIChkZWNyZWFzaW5nKVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBrZXkgPC0gcm93W1sxXV1cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKCFpcy5uYShrZXkpKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdmFsdWUgPC0gYXMubnVtZXJpYyhyb3dbWzJdXSkvYWJzKGFzLm51bWVyaWMocm93W1syXV0pKVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNldE5hbWVzKGxpc3QodmFsdWUpLCBrZXkpXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0gXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9KSAlPiVcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRmlsdGVyKGZ1bmN0aW9uKHgpICFpcy5udWxsKHgpLCAuKSAlPiVcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdW5saXN0KHJlY3Vyc2l2ZT1GQUxTRSlcbmBgYFxuYGBgIn0= -->

```r
```r
# Top immunome features from the univariate analysis on OOL data
# we associate a coeff +1 (increasing) or -1 (decreasing) to the features

univariate.OOL.features <- apply(spearman_cor[abs(spearman_cor$`Spearman corr`) > 0.3,], # taking features with |Spearmanr| > 0.3
                                 1,
                                 function(row){ # associating the feature name to +1 (increasing) or -1 (decreasing)
                                   key <- row[[1]]
                                   if (!is.na(key)) {
                                     value <- as.numeric(row[[2]])/abs(as.numeric(row[[2]]))
                                     setNames(list(value), key)
                                   } 
                                 }) %>%
                                Filter(function(x) !is.null(x), .) %>%
                                unlist(recursive=FALSE)

<!-- rnb-source-end -->

<!-- rnb-chunk-end -->


<!-- rnb-text-begin -->


**Top features from feature.index**


<!-- rnb-text-end -->


<!-- rnb-chunk-begin -->


<!-- rnb-source-begin eyJkYXRhIjoiYGBgclxuYGBgclxuIyBUb3AgaW1tdW5vbWUgZmVhdHVyZXMgZnJvbSB0aGUgZmVhdHVyZS5pbmRleFxuIyB3ZSBhc3NvY2lhdGUgYSBjb2VmZiArMSAoaW5jcmVhc2luZykgb3IgLTEgKGRlY3JlYXNpbmcpIHRvIHRoZSBmZWF0dXJlc1xuXG4jIFRpbWVwb2ludCBvZiBpbnRlcmVzdFxuVFRMIDwtIC04NFxuXG4jIFRocmVzaG9sZHMgdG8gY2FsY3VsYXRlIHRoZSBub3JtYWwgYmVoYXZpb3Igb2YgYSBnaXZlbiBmZWF0dXJlXG5ub3JtYWwuYmVoYXZpb3Iuc2xvcGUudGhyZXNob2xkIDwtIDAuXG5ub3JtYWwuYmVoYXZpb3IucHZhbC50aHJlc2hvbGQgPC0gMTBcblxuIyBJbmZvIChtb2RlbCwgcHZhbCwgcm1zZSwgLi4uKSBvZiB0aGUgbW9kZWxzIGF0IHRoZSB0aW1lcG9pbnQgVFRMXG5tb2RlbC5pbmZvIDwtIG1lcmdlKGRmX21vZGVscywgY3VydmUuY2xhc3NpZmljYXRpb24sIGJ5LnggPSBcXGZlYXR1cmVcXCwgYnkueSA9IFxcY3l0b2ZcXCkgJT4lXG4gICAgICAgICAgICAgIHJvd3dpc2UoKSAlPiVcbiAgICAgICAgICAgICAgbXV0YXRlKG5vcm1hbC5iZWhhdmlvciA9IGZlYXR1cmUubm9ybWFsLmJlaGF2aW9yLmF0LlRUTChtb2RlbCxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwdmFsLCBcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBub3JtYWwuYmVoYXZpb3Iuc2xvcGUudGhyZXNob2xkLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5vcm1hbC5iZWhhdmlvci5wdmFsLnRocmVzaG9sZCxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRUTCkpXG4jIExpc3Qgb2YgdGhlIGZlYXR1cmVzIGFuZCB0aGVpciBiZWhhdmlvclxudG9wLmZlYXR1cmUuaW5kZXggPC0gZmVhdHVyZS5pbmRleCAlPiVcbiAgICAgICAgICAgICAgICAgICAgICAgIGZpbHRlcihtb2RlbF9pbmRleCA+IDApICU+JVxuICAgICAgICAgICAgICAgICAgICAgICAgbGVmdF9qb2luKG1vZGVsLmluZm8sIGJ5PVxcZmVhdHVyZVxcKSAlPiVcbiAgICAgICAgICAgICAgICAgICAgICAgIHNlbGVjdChmZWF0dXJlLCBub3JtYWwuYmVoYXZpb3IpICU+JVxuICAgICAgICAgICAgICAgICAgICAgICAgcHVsbChub3JtYWwuYmVoYXZpb3IpICU+JSBcbiAgICAgICAgICAgICAgICAgICAgICAgIHNldE5hbWVzKHB1bGwoZmVhdHVyZS5pbmRleFsoZmVhdHVyZS5pbmRleCRtb2RlbF9pbmRleCA+IDApICYgIShpcy5uYShmZWF0dXJlLmluZGV4JG1vZGVsX2luZGV4KSksXSwgXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZlYXR1cmUpKSAlPiVcbiAgICAgICAgICAgICAgICAgICAgICAgIGFzLmxpc3QoKVxuYGBgXG5gYGAifQ== -->

```r
```r
# Top immunome features from the feature.index
# we associate a coeff +1 (increasing) or -1 (decreasing) to the features

# Timepoint of interest
TTL <- -84

# Thresholds to calculate the normal behavior of a given feature
normal.behavior.slope.threshold <- 0.
normal.behavior.pval.threshold <- 10

# Info (model, pval, rmse, ...) of the models at the timepoint TTL
model.info <- merge(df_models, curve.classification, by.x = \feature\, by.y = \cytof\) %>%
              rowwise() %>%
              mutate(normal.behavior = feature.normal.behavior.at.TTL(model,
                                                                      pval, 
                                                                      normal.behavior.slope.threshold,
                                                                      normal.behavior.pval.threshold,
                                                                     TTL))
# List of the features and their behavior
top.feature.index <- feature.index %>%
                        filter(model_index > 0) %>%
                        left_join(model.info, by=\feature\) %>%
                        select(feature, normal.behavior) %>%
                        pull(normal.behavior) %>% 
                        setNames(pull(feature.index[(feature.index$model_index > 0) & !(is.na(feature.index$model_index)),], 
                                      feature)) %>%
                        as.list()

<!-- rnb-source-end -->

<!-- rnb-chunk-end -->


<!-- rnb-text-begin -->


### Drugs ranking

Here we rank the drugs based on their effect on the chosen features of interest. We associate a +1 score when the drug has an effect which is opposite to the "normal" behavior/ trend of the feature and -1 when the effect of the drug is colinear to the "normal" feature behavior.


<!-- rnb-text-end -->


<!-- rnb-chunk-begin -->


<!-- rnb-source-begin eyJkYXRhIjoiYGBgclxuYGBgclxuIyBNb2RlbHMgb2YgaW50ZXJlc3RcbmZpbmFsLm1vZGVsIDwtIHBzZXVkb19sb2cxMC5tZWRpYW4ubGluZWFyLm1vZGVsXG5maW5hbC5tb2RlbC50eXBlIDwtIFxcbWVkaWFuXFwgI1xcaW5kaXZpZHVhbFxcIG9yIFxcbWl4ZWRcXCBvciBcXG1lZGlhblxcXG5cbiMgQ2hvc2luZyBmZWF0dXJlcyBvZiBpbnRlcmVzdFxuZmVhdHVyZV9jaG9pY2UgPC0gXFx0b3BfZmVhdHVyZV9pbmRleF9mZWF0dXJlc1xcXG5PT0xfZmVhdHVyZXMgPC0gdG9wLmZlYXR1cmUuaW5kZXhcblxuIyBDaG9zaW5nIHRocmVzaG9sZHMgb3ZlciBvciB1bmRlciB3aGljaCB3ZSBjb25zaWRlciB0aGUgZWZmZWN0IG9mIHRoZSBkcnVnIGFzIHJlbGV2YW50XG5zbG9wZS50aHJlc2hvbGQgPC0gMFxucHZhbC50aHJlc2hvbGQgPC0gMVxuYGBgXG5gYGAifQ== -->

```r
```r
# Models of interest
final.model <- pseudo_log10.median.linear.model
final.model.type <- \median\ #\individual\ or \mixed\ or \median\

# Chosing features of interest
feature_choice <- \top_feature_index_features\
OOL_features <- top.feature.index

# Chosing thresholds over or under which we consider the effect of the drug as relevant
slope.threshold <- 0
pval.threshold <- 1

<!-- rnb-source-end -->

<!-- rnb-chunk-end -->


<!-- rnb-text-begin -->


Calculation of the scores and ranking of the features.

**drug.ranking :** dataframe containing the name of the drugs and their score.


<!-- rnb-text-end -->


<!-- rnb-chunk-begin -->


<!-- rnb-source-begin eyJkYXRhIjoiYGBgclxuYGBgclxuZHJ1Zy5yYW5raW5nIDwtIGRhdGEuZnJhbWUoZHJ1ZyA9IGNoYXJhY3RlcigpLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgc2NvcmUgPSBudW1lcmljKCksXG4gICAgICAgICAgICAgICAgICAgICAgICAgICBzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UpXG5cbiMgR2V0dGluZyBhIG5vcm1pemVkIGxvZyB0cmFuc2Zvcm0gb2YgdGhlIGZlYXR1cmUgaW5kZXggdG8gYmUgdXNlZCBhcyBjb2VmZmljaWVudCBpbiB0aGUgc2NvcmVcbm5vcm0ubG9nLmZlYXR1cmUuaW5kZXggPC0gZmVhdHVyZS5pbmRleCAlPiVcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBtdXRhdGUobG9nLm1vZGVsX2luZGV4ID0gbG9nMTAoMSArIG1vZGVsX2luZGV4KSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbm9ybS5sb2cubW9kZWxfaW5kZXggPSBsb2cubW9kZWxfaW5kZXgvc3VtKGxvZy5tb2RlbF9pbmRleCwgbmEucm09VFJVRSkpICU+JVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNlbGVjdChmZWF0dXJlLCBub3JtLmxvZy5tb2RlbF9pbmRleCkgJT4lXG4gICAgICAgICAgICAgICAgICAgICAgICBwdWxsKG5vcm0ubG9nLm1vZGVsX2luZGV4KSAlPiUgXG4gICAgICAgICAgICAgICAgICAgICAgICBzZXROYW1lcyhwdWxsKGZlYXR1cmUuaW5kZXgsIGZlYXR1cmUpKSAlPiVcbiAgICAgICAgICAgICAgICAgICAgICAgIGFzLmxpc3QoKVxuXG4jIENhbGN1bGF0aW5nIHRoZSBzY29yZVxuZm9yIChkcnVnIGluIHVuaXF1ZShmaW5hbC5tb2RlbCRkcnVnKSl7XG4gIHNjb3JlIDwtIDBcbiAgIyBXZSBzdW0gdGhlIHNjb3JlcyBvdmVyIGFsbCB0aGUgZmVhdHVyZXMgZm9yIGVhY2ggZHJ1Z1xuICBmb3IgKGZlYXR1cmUgaW4gbmFtZXMoT09MX2ZlYXR1cmVzKSl7XG4gICAgIyBHZXR0aW5nIHRoZSBkcnVnIGVmZmVjdCBvbiB0aGUgZmVhdHVyZVxuICAgIHNsb3BlIDwtIG1vZGVsLnNjb3Jlc1sobW9kZWwuc2NvcmVzJGZlYXR1cmUgPT0gZmVhdHVyZSkgJiAobW9kZWwuc2NvcmVzJGRydWcgPT0gZHJ1ZyksXSRzbG9wZVxuICAgIHB2YWwgPC0gbW9kZWwuc2NvcmVzWyhtb2RlbC5zY29yZXMkZmVhdHVyZSA9PSBmZWF0dXJlKSAmIChtb2RlbC5zY29yZXMkZHJ1ZyA9PSBkcnVnKSxdJHB2YWxcbiAgICAjIFNvbWV0aW1lcyB0aGUgdmFsdWVzIG9mIHNsb3BlIGFuZC9vciBwdmFsIGlzIGVtcHR5IHNvIHdlIGZpbGwgd2l0aCAwIHRoZXNlIHZhbHVlc1xuICAgIGRydWdfZWZmZWN0IDwtIGlmZWxzZSgobGVuZ3RoKHNsb3BlKSpsZW5ndGgocHZhbCkgPT0gMCkgfHwgKGlzLm5hKHNsb3BlKSB8IGlzLm5hKHB2YWwpKSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgMCxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgZHJ1Zy5lZmZlY3Qoc2xvcGUsIHB2YWwsIHNsb3BlLnRocmVzaG9sZCwgcHZhbC50aHJlc2hvbGQpKVxuICAgICMgQWRkaW5nIHRoZSBpbmRpdmlkdWFsIHNjb3JlcyBvZiB0aGUgZHJ1ZyBlYWNoIGZlYXR1cmUgXG4gICAgc2NvcmUgPC0gc2NvcmUgLSBkcnVnX2VmZmVjdCpPT0xfZmVhdHVyZXNbW2ZlYXR1cmVdXSpub3JtLmxvZy5mZWF0dXJlLmluZGV4W1tmZWF0dXJlXV1cbiAgfVxuICAjIEFkZGluZyB0aGUgZHJ1ZyBhbmQgaXRzIHNjb3JlIHRvIGRydWcucmFua2luZ1xuICBkcnVnLnJhbmtpbmcgPC0gcmJpbmQoZHJ1Zy5yYW5raW5nLFxuICAgICAgICAgICAgICAgICAgICAgICAgZGF0YS5mcmFtZShkcnVnPWRydWcsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNjb3JlPXNjb3JlLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UpKVxufVxuIyBBcnJhbmdpbmcgdGhlIGRydWdzIHRvIHNlZSB0aGUgYmVzdCBkcnVncyBvbiB0b3BcbmRydWcucmFua2luZyA8LSBkcnVnLnJhbmtpbmcgJT4lIGFycmFuZ2UoZGVzYyhzY29yZSkpXG5kcnVnLnJhbmtpbmdcbmBgYFxuYGBgIn0= -->

```r
```r
drug.ranking <- data.frame(drug = character(),
                           score = numeric(),
                           stringsAsFactors = FALSE)

# Getting a normized log transform of the feature index to be used as coefficient in the score
norm.log.feature.index <- feature.index %>%
                            mutate(log.model_index = log10(1 + model_index),
                                   norm.log.model_index = log.model_index/sum(log.model_index, na.rm=TRUE)) %>%
                            select(feature, norm.log.model_index) %>%
                        pull(norm.log.model_index) %>% 
                        setNames(pull(feature.index, feature)) %>%
                        as.list()

# Calculating the score
for (drug in unique(final.model$drug)){
  score <- 0
  # We sum the scores over all the features for each drug
  for (feature in names(OOL_features)){
    # Getting the drug effect on the feature
    slope <- model.scores[(model.scores$feature == feature) & (model.scores$drug == drug),]$slope
    pval <- model.scores[(model.scores$feature == feature) & (model.scores$drug == drug),]$pval
    # Sometimes the values of slope and/or pval is empty so we fill with 0 these values
    drug_effect <- ifelse((length(slope)*length(pval) == 0) || (is.na(slope) | is.na(pval)),
                          0,
                          drug.effect(slope, pval, slope.threshold, pval.threshold))
    # Adding the individual scores of the drug each feature 
    score <- score - drug_effect*OOL_features[[feature]]*norm.log.feature.index[[feature]]
  }
  # Adding the drug and its score to drug.ranking
  drug.ranking <- rbind(drug.ranking,
                        data.frame(drug=drug,
                                   score=score,
                                   stringsAsFactors = FALSE))
}
# Arranging the drugs to see the best drugs on top
drug.ranking <- drug.ranking %>% arrange(desc(score))
drug.ranking

<!-- rnb-source-end -->

<!-- rnb-frame-begin eyJtZXRhZGF0YSI6eyJjbGFzc2VzIjoiZGF0YS5mcmFtZSIsIm5yb3ciOjE1LCJuY29sIjoyLCJzdW1tYXJ5Ijp7IkRlc2NyaXB0aW9uIjoiZGYgWzE1IMOXIDJdIn19LCJyZGYiOiJINHNJQUFBQUFBQUFBMTFTUVdnVFFSU2Rick9XcEdrVENZSTN2WGxLRUtwaVRwRkdLeFVMYmFoUUVhclQzVWt5T2p0L21aM1VXSkI2TENLQzRFRlB2WXNndllrS28wUnFLWjVFallkZVJJUjZFY0dqMkhZMjNkbVVIZGpaUCsvLzkvNy9NNzkyZm00c001ZEJDQTJpMUtEZWJXMGkrOHJzUlBFc1FpbExId1pRQ3FYRGYxdTdDOW9Jd2J6K2NwRWpQVVZrSFlSSHVRRnF0STRYV3JJUFRJSkwyNWdEaTREc1pjd0Q4QVZlQWtZaXJLQmxtbmVZTDRnTG5BYkFnQnZYMENRMFNUdG1EMDloWDRDa2pNWVIrWEhDbHpTWmNPcFF4dUxNMldrQkRSSklJdnBxdWhvZmU5U045VElUd0toekhEdlVOVWlWMUVIaU52VU1LVnRsSUFYMURsWThXbTB5RUxLSm1SYUw1WWVuQlY3RWdjUmgvem9vdktuS2xyWDJjL051cC9KcGZmbG9ZV2Fsb2dKditkM2E0OHFyaTg5T1AxMC9wVHJvMFE4OHU2MDY4OTBIOCtNMzFQdm5WNzEvcTF2cXc4T1h1ZDIvV2JWeFpPYk1tMnN2MUNiN2MvSStMcXZQNVhQaWQrT3crdkw5N1lVbjEydnE2d212dTdLeHFMcjVxZTJicjMrcGI1ZksvNDk5WEUwOG9jMnhSNExvK2F3SVRMbWkxVEFCZ1FPQ0pGaHBBYmRMaGprU011K2gzc29sNVIyR0F5TnZ3SXlMSlM3VmhlYnIwMDZDTWdTK3BNQTF5UXBIeTA2UUIwUUN5TFY0V0lsYmRKb3RmcXM0Rmlib3VmZlhTR1RuRHRqV2ZrcHJONUt5STZsRGhEZjZBMlF6dkVETVFJenFqbnNObDN4QnVUU2RhRFFvU1QwWDhlQTR3QXpTNnczdDdBR28wUTNiVVFNQUFBPT0ifQ== -->

<div data-pagedtable="false">
  <script data-pagedtable-source type="application/json">
{"columns":[{"label":["drug"],"name":[1],"type":["chr"],"align":["left"]},{"label":["score"],"name":[2],"type":["dbl"],"align":["right"]}],"data":[{"1":"Metformin","2":"0.4376645"},{"1":"Rifabutin","2":"0.2933653"},{"1":"Iodixanol","2":"0.1228550"},{"1":"Lansoprazole","2":"0.1026560"},{"1":"Methylpredonisolone","2":"-0.1484549"},{"1":"Iohexol","2":"-0.1513318"},{"1":"Maprotiline","2":"-0.1615097"},{"1":"Benzylpenicillin","2":"-0.1840429"},{"1":"Progesterone","2":"-0.1881506"},{"1":"Iopamidol","2":"-0.2064495"},{"1":"Folic acid","2":"-0.3159944"},{"1":"Cefotaxime","2":"-0.3419038"},{"1":"Clotrimazole","2":"-0.3461566"},{"1":"Chlorthalidone","2":"-0.3603701"},{"1":"Pravastatin","2":"-0.3795304"}],"options":{"columns":{"min":{},"max":[10],"total":[2]},"rows":{"min":[10],"max":[10],"total":[15]},"pages":{}}}
  </script>
</div>

<!-- rnb-frame-end -->

<!-- rnb-chunk-end -->


<!-- rnb-text-begin -->


## Visualization

### Models versus "normal" behavior

Auxiliary function to plot the mixed model.


<!-- rnb-text-end -->


<!-- rnb-chunk-begin -->


<!-- rnb-source-begin eyJkYXRhIjoiYGBgclxuYGBgclxuIyBGdW5jdGlvbiB0YWtpbmcgdGhlIG5hbWUgb2YgYSBmZWF0dXJlLCBuYW1lIG9mIGEgZHJ1ZyBhbmQgYSBwdmFsdWVcbiMgUmV0dXJuaW5nIGEgcGxvdCBvZiB0aGUgbW9kZWwgY29ycmVzcG9uZGluZyB0byB0aGUgZmVhdHVyZSBhbmQgZHJ1Z1xuXG5wbG90X2RydWdfZmVhdHVyZV9tb2RlbCA8LSBmdW5jdGlvbih0YXJnZXRfZHJ1ZywgdGFyZ2V0X2ZlYXR1cmUsIHBfdmFsdWUpe1xuICAjIEdldHRpbmcgdGhlIG1vZGVsIGFzc29jaWF0ZWQgdG8gdGhlIHRhcmdldF9kcnVnIGFuZCB0aGUgdGFyZ2V0X2ZlYXR1cmVcbiAgdGFyZ2V0X21vZGVsIDwtIGZpbmFsLm1vZGVsJG1vZGVsW2ZpbmFsLm1vZGVsJGZlYXR1cmUgPT0gdGFyZ2V0X2ZlYXR1cmUgJiBmaW5hbC5tb2RlbCRkcnVnID09IHRhcmdldF9kcnVnXVtbMV1dXG4gICMgR2V0dGluZyB0aGUgcHZhbCBhc3NvY2lhdGVkIHdpdGggdGhlIHRhcmdldF9tb2RlbFxuICBwdmFsIDwtIGZpbmFsLm1vZGVsJHB2YWxbZmluYWwubW9kZWwkZmVhdHVyZSA9PSB0YXJnZXRfZmVhdHVyZSAmIGZpbmFsLm1vZGVsJGRydWcgPT0gdGFyZ2V0X2RydWddW1sxXV1cbiAgIyBTZXR0aW5nIHRoZSBkb3NlIHZhbHVlcyB0byB0aGVpciBwc2V1ZG8gbG9nIHRyYW5zZm9ybVxuICBEb3NlcmVzcG9uc2UgPC0gQWxsUGVuRG9zZXJlc3BvbnNlICU+JVxuICAgICAgICAgICAgICAgICAgICBtdXRhdGUoZG9zZSA9IHBzZXVkb19sb2dfZG9zZSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgIElEID0gYXMuZmFjdG9yKElEKSkgJT4lXG4gICAgICAgICAgICAgICAgICAgIGZpbHRlcihpcy5maW5pdGUoZG9zZSkpXG4gICMgU3Vic2V0IG9mIHRoZSBkYXRhIGZvciB0aGUgY2hvc2VuIGZlYXR1cmUgYW5kIGRydWdcbiAgZGF0YSA8LSBEb3NlcmVzcG9uc2UgJT4lIFxuICAgICAgICAgICAgICBmaWx0ZXIoZmVhdHVyZSA9PSAhIXRhcmdldF9mZWF0dXJlLFxuICAgICAgICAgICAgICAgICAgICAgZHJ1ZyA9PSAhIXRhcmdldF9kcnVnKSAlPiVcbiAgICAgICAgICAgICAgc2VsZWN0KElELCBkb3NlLCB2YWx1ZSlcbiAgICBcbiAgIyMjIFBMT1QgVEhFIE1FRElBTiBNT0RFTFxuICBpZiAoZmluYWwubW9kZWwudHlwZSA9PSBcXG1lZGlhblxcKXtcbiAgICAjIENvZWZmaWNpZW50cyBvZiB0aGUgc2VsZWN0ZWQgbW9kZWxcbiAgICBtb2RlbF9jb2VmcyA8LSBjb2VmKHRhcmdldF9tb2RlbCkgJT4lXG4gICAgICAgICAgICAgICAgICAgICAgYXMuZGF0YS5mcmFtZSgpICU+JVxuICAgICAgICAgICAgICAgICAgICAgIHQoKSAlPiVcbiAgICAgICAgICAgICAgICAgICAgICBgY29sbmFtZXM8LWAoYyhcXEludGVyY2VwdFxcLCBcXFNsb3BlXFwpKVxuICAgIFxuICAgIGRhdGFfcmFuaSA8LSBtZXJnZShkYXRhLCBtb2RlbF9jb2VmcylcbiAgICBcbiAgICAjIFBsb3RcbiAgICBwbG90IDwtIGdncGxvdChkYXRhX3JhbmksIGFlcyh4PWRvc2UsIHk9dmFsdWUsIGdyb3VwPWRvc2UpKSArXG4gICAgICAgICAgICAgIGdlb21fYm94cGxvdCgpICtcbiAgICAgICAgICAgICAgZ2VvbV9hYmxpbmUoYWVzKGludGVyY2VwdCA9IEludGVyY2VwdCwgXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzbG9wZSA9IFNsb3BlKSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgc2l6ZSA9IDEuKSArXG4gICAgICAgICAgICAgIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9IFxcdG9wXFwpXG4gIH1cbiAgXG4gICMjIyBQTE9UIFRIRSBJTkRJVklEVUFMIE1PREVMXG4gIGlmIChmaW5hbC5tb2RlbC50eXBlID09IFxcaW5kaXZpZHVhbFxcKXtcbiAgICAjIENvZWZmaWNpZW50cyBvZiB0aGUgc2VsZWN0ZWQgbW9kZWxcbiAgICBtb2RlbF9jb2VmcyA8LSB0YXJnZXRfbW9kZWxzICU+JVxuICAgICAgICAgICAgICAgICAgICAgIG11dGF0ZShTbG9wZSA9IHNhcHBseShtb2RlbCwgZnVuY3Rpb24oeCkgY29lZih4KVtcXGRvc2VcXF0pLFxuICAgICAgICAgICAgICAgICAgICAgIEludGVyY2VwdCA9IHNhcHBseShtb2RlbCwgZnVuY3Rpb24oeCkgY29lZih4KVtcXChJbnRlcmNlcHQpXFxdKSxcbiAgICAgICAgICAgICAgICAgICAgICBJRCA9IGFzLmZhY3RvcihJRCkpXG4gICAgXG4gICAgZGF0YV9yYW5pIDwtIGxlZnRfam9pbihkYXRhLCBtb2RlbF9jb2VmcywgYnkgPSBcXElEXFwpXG4gICAgXG4gICAgIyBQbG90XG4gICAgcGxvdCA8LSBnZ3Bsb3QoZGF0YSA9IGRhdGFfcmFuaSwgbWFwcGluZyA9IGFlcyh4ID0gZG9zZSwgeSA9IHZhbHVlLCBjb2xvdXIgPSBJRCkpICtcbiAgICAgICAgICAgICAgZ2VvbV9wb2ludChuYS5ybSA9IFQsIGFscGhhID0gMC41KSArXG4gICAgICAgICAgICAgIGdlb21fYWJsaW5lKGFlcyhpbnRlcmNlcHQgPSBJbnRlcmNlcHQsIHNsb3BlID0gU2xvcGUsIGNvbG91ciA9IElEKSwgXG4gICAgICAgICAgICAgICAgICAgICAgICAgIHNpemUgPSAxLikgK1xuICAgICAgICAgICAgICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSBcXHRvcFxcKVxuICB9XG4gIFxuICAjIyMgUExPVCBUSEUgTUlYRUQgTElORUFSIE1PREVMXG4gIGlmIChmaW5hbC5tb2RlbC50eXBlID09IFxcbWl4ZWRcXCl7XG4gICAgIyBDb2VmZmljaWVudHMgb2YgdGhlIHNlbGVjdGVkIG1vZGVsXG4gICAgbW9kZWxfY29lZnMgPC0gY29lZih0YXJnZXRfbW9kZWwpJElEICU+JSBcbiAgICAgICAgICAgICAgICAgICAgICByZW5hbWUoSW50ZXJjZXB0ID0gYChJbnRlcmNlcHQpYCwgU2xvcGUgPSBkb3NlKSAlPiUgXG4gICAgICAgICAgICAgICAgICAgICAgcm93bmFtZXNfdG9fY29sdW1uKFxcSURcXClcbiAgICBcbiAgICBkYXRhX3JhbmkgPC0gbGVmdF9qb2luKGRhdGEsIG1vZGVsX2NvZWZzLCBieSA9IFxcSURcXClcbiAgICBcbiAgICAjIFBsb3RcbiAgICBwbG90IDwtIHN1cHByZXNzV2FybmluZ3MoZ2dwbG90KGRhdGEgPSBkYXRhX3JhbmksIFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4ID0gZG9zZSwgXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHkgPSB2YWx1ZSwgXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG91ciA9IElEKSkgK1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdlb21fcG9pbnQobmEucm0gPSBULCBhbHBoYSA9IDAuNSkgK1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdlb21fYWJsaW5lKGFlcyhpbnRlcmNlcHQgPSBJbnRlcmNlcHQsIFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzbG9wZSA9IFNsb3BlLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvdXIgPSBJRCksXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2l6ZSA9IDEuKSlcbiAgfVxuICBcbiAgIyBSZW1vdmluZyB1bmVjZXNzYXJ5IGxhYmVscyBhbmQgYWRkaW5nIHRpdGxlXG4gIHBsb3QgPC0gcGxvdCArIFxuICAgICAgZ2d0aXRsZShwYXN0ZSh0YXJnZXRfZmVhdHVyZSwgcHZhbCwgc2VwPVxcXG5gYGAifQ== -->

```r
```r
# Function taking the name of a feature, name of a drug and a pvalue
# Returning a plot of the model corresponding to the feature and drug

plot_drug_feature_model <- function(target_drug, target_feature, p_value){
  # Getting the model associated to the target_drug and the target_feature
  target_model <- final.model$model[final.model$feature == target_feature & final.model$drug == target_drug][[1]]
  # Getting the pval associated with the target_model
  pval <- final.model$pval[final.model$feature == target_feature & final.model$drug == target_drug][[1]]
  # Setting the dose values to their pseudo log transform
  Doseresponse <- AllPenDoseresponse %>%
                    mutate(dose = pseudo_log_dose,
                           ID = as.factor(ID)) %>%
                    filter(is.finite(dose))
  # Subset of the data for the chosen feature and drug
  data <- Doseresponse %>% 
              filter(feature == !!target_feature,
                     drug == !!target_drug) %>%
              select(ID, dose, value)
    
  ### PLOT THE MEDIAN MODEL
  if (final.model.type == \median\){
    # Coefficients of the selected model
    model_coefs <- coef(target_model) %>%
                      as.data.frame() %>%
                      t() %>%
                      `colnames<-`(c(\Intercept\, \Slope\))
    
    data_rani <- merge(data, model_coefs)
    
    # Plot
    plot <- ggplot(data_rani, aes(x=dose, y=value, group=dose)) +
              geom_boxplot() +
              geom_abline(aes(intercept = Intercept, 
                              slope = Slope),
                          size = 1.) +
              theme(legend.position = \top\)
  }
  
  ### PLOT THE INDIVIDUAL MODEL
  if (final.model.type == \individual\){
    # Coefficients of the selected model
    model_coefs <- target_models %>%
                      mutate(Slope = sapply(model, function(x) coef(x)[\dose\]),
                      Intercept = sapply(model, function(x) coef(x)[\(Intercept)\]),
                      ID = as.factor(ID))
    
    data_rani <- left_join(data, model_coefs, by = \ID\)
    
    # Plot
    plot <- ggplot(data = data_rani, mapping = aes(x = dose, y = value, colour = ID)) +
              geom_point(na.rm = T, alpha = 0.5) +
              geom_abline(aes(intercept = Intercept, slope = Slope, colour = ID), 
                          size = 1.) +
              theme(legend.position = \top\)
  }
  
  ### PLOT THE MIXED LINEAR MODEL
  if (final.model.type == \mixed\){
    # Coefficients of the selected model
    model_coefs <- coef(target_model)$ID %>% 
                      rename(Intercept = `(Intercept)`, Slope = dose) %>% 
                      rownames_to_column(\ID\)
    
    data_rani <- left_join(data, model_coefs, by = \ID\)
    
    # Plot
    plot <- suppressWarnings(ggplot(data = data_rani, 
                                    mapping = aes(x = dose, 
                                                  y = value, 
                                                  colour = ID)) +
                               geom_point(na.rm = T, alpha = 0.5) +
                               geom_abline(aes(intercept = Intercept, 
                                               slope = Slope,
                                               colour = ID),
                                           size = 1.))
  }
  
  # Removing unecessary labels and adding title
  plot <- plot + 
      ggtitle(paste(target_feature, pval, sep=\

Plotting the individual models of the drug on the chosen features versus the normal behavior of the OOL feature in order to see if the trends are actually opposites (or colinear) and that the models fit the data.

```r
# Selecting a specific drug and plotting the comparison of the model of the features with the mixed model of the drug
target_drug <- \Metformin\
# Time to labor of interest (will plot the derivative at this point)
TTL <- -84

plots <- list()
i <- 0
for (target_feature in names(OOL_features)) {
  target_model <- final.model$model[final.model$feature == target_feature & final.model$drug == target_drug]
  pval <- model.scores[(model.scores$feature == target_feature) & (model.scores$drug == target_drug),]$pval
  
  # We only plot features on which the score has been calculated (with mixed model having a pvalue < pval < pval.threshold)
  if ((length(pval) > 0) &&
      (!is.na(pval)) &&
      (pval < pval.threshold) && 
      (length(target_model)>0)){
    # Counting the number of plots
    i <- i + 2
    
    ### PLOT THE INDIVIDUAL LINEAR MODEL
    model_coef_plot <- plot_drug_feature_model(target_drug, target_feature, pval)
    # Adding plot to the list of plots
    plots[[target_feature]] <- model_coef_plot

    
    ### PLOT THE ASSOCIATED OOL FEATURE
    # Getting the coefficients and class of the model
    coefs <- df_models[df_models$feature == target_feature,]$model[[1]][[1]]
    
    # Building the predictions
    y <- OOL_data[, target_feature]
    intercept <- coefs[['(Intercept)']]
    if (length(coefs) == 3){ # quadratic model
  
      a <- coefs[['DOS2']]
      b <- coefs[['DOS']]
      y_pred <- intercept + b * DOS + a * DOS^2
      y_deriv <- (2*a*TTL + b)*(DOS - TTL) + (intercept + b * TTL + a * TTL^2)
    }
    else{ # length(coefs) == 2, linear model
      slope <- coefs[['DOS']]
      y_pred <- intercept + slope * DOS
      y_deriv <- slope*(DOS - TTL) + (intercept + slope * TTL)
    }
    df <- data.frame(x = DOS, y = y, y_pred = y_pred, y_deriv = y_deriv)
    
    # Getting pvalue of the model
    pval <- curve.classification[curve.classification$cytof == target_feature,]$pval
    # Plot
    plot <- ggplot(df, aes(x = x, y = y)) +
      geom_point(color = \blue\, alpha = 0.5, size = 1) +
      geom_line(aes(y = y_pred), color = \red\, size = 0.7) +
      geom_line(aes(y = y_deriv), linetype = \dashed\, color = \red\, size = 0.7) +
      geom_vline(xintercept = TTL, linetype = \dashed\, color = \red\, size = 0.7) +
      ggtitle(paste(target_feature, pval, sep=\
null device 
          1 

Global visualization : heatmap

```r
# Function to plot the pheatmap of the final drug effect
plot_pheatmap <- function(drug.name, drug.final.effect.dataframe, clustering_rows, clustering_cols, dendro=FALSE){
  my_colors <- c(\blue\, rgb(0, 0, 1, alpha = 0.5), \white\, rgb(1, 0, 0, alpha = 0.5), \red\)
  
  # Preparing the data
  data <- as.matrix(drug.final.effect.dataframe[, -1])
  rownames(data) <- drug.final.effect.dataframe$population
  data[is.na(data)] <- 0
  
  # Reorganizing rows and columns
  row_order <- order.dendrogram(as.dendrogram(clustering_rows))
  col_order <- order.dendrogram(as.dendrogram(clustering_cols))
  data <- data[row_order, col_order]
  
  # Plot
  pheatmap(data, 
           color = my_colors,
           na_color = \grey\,
           cluster_rows = dendro, 
           cluster_cols = dendro,
           main = drug.name,
           cellwidth = 10, 
           cellheight = 10,
           legend_breaks = c(-1, -0.5, 0, 0.5, 1),
           legend_labels = c(\Drug effect colinear\nto normal pregnancy\,
                             \\,
                             \Missing Value\nor\nNot significant\,
                             \\,
                             \Drug effect opposite\nto normal pregnancy\)
           )
}

<!-- rnb-source-end -->

<!-- rnb-chunk-end -->


<!-- rnb-text-begin -->


Saving the heat maps for a chosen set of thresholds.


<!-- rnb-text-end -->


<!-- rnb-chunk-begin -->


<!-- rnb-source-begin eyJkYXRhIjoiYGBgclxuYGBgclxuIyBQYXJhbWV0ZXJzIGZvciB0aGUgaGVhdCBtYXAgc2NvcmVzXG5UVEwgPC0gLTg0XG5ub3JtYWwuYmVoYXZpb3IucHZhbC50aHJlc2hvbGQgPC0gMS5cbm5vcm1hbC5iZWhhdmlvci5zbG9wZS50aHJlc2hvbGQgPC0gMC5cbmRydWcucHZhbC50aHJlc2hvbGQgPC0gMS5cbmRydWcuc2xvcGUudGhyZXNob2xkIDwtIDAuXG5mZWF0dXJlcy5vZi5pbnRlcmVzdCA8LSBuYW1lcyh0b3AuZmVhdHVyZS5pbmRleClcbnJlZi5jbHVzdGVyaW5nLmZlYXR1cmUgPC0gXFxNZXRmb3JtaW5cXFxuXG4jIEJ1aWxkaW5nIHRoZSBjbHVzdGVyaW5nIG9mIHJlZmVyZW5jZSBmb3IgYWxsIHRoZSBoZWF0bWFwc1xucmVmX2RhdGEgPC0gY3JlYXRlLmRydWcuZWZmZWN0LmRhdGEuZnJhbWUoXG4gICAgICAgICAgICAgICAgICByZWYuY2x1c3RlcmluZy5mZWF0dXJlLFxuICAgICAgICAgICAgICAgICAgbm9ybWFsLmJlaGF2aW9yLnB2YWwudGhyZXNob2xkLCBcbiAgICAgICAgICAgICAgICAgIG5vcm1hbC5iZWhhdmlvci5zbG9wZS50aHJlc2hvbGQsIFxuICAgICAgICAgICAgICAgICAgZHJ1Zy5wdmFsLnRocmVzaG9sZCwgXG4gICAgICAgICAgICAgICAgICBkcnVnLnNsb3BlLnRocmVzaG9sZCxcbiAgICAgICAgICAgICAgICAgIFRUTCxcbiAgICAgICAgICAgICAgICAgIGZlYXR1cmVzLm9mLmludGVyZXN0KVxuZGF0YSA8LSBhcy5tYXRyaXgocmVmX2RhdGFbLCAtMV0pXG5yb3duYW1lcyhkYXRhKSA8LSByZWZfZGF0YSRwb3B1bGF0aW9uXG5kYXRhW2lzLm5hKGRhdGEpXSA8LSAwXG5jbHVzdGVyaW5nX3Jvd3MgPC0gaGNsdXN0KGRpc3QoZGF0YSkpXG5jbHVzdGVyaW5nX2NvbHMgPC0gaGNsdXN0KGRpc3QodChkYXRhKSkpXG5cblxuIyBQbG90dGluZyBhbGwgdGhlIGhlYXQgbWFwc1xucGRmKHBhc3RlKGRydWdfYXNzYXlfcGF0aCwgXFwvcGxvdHMvRHJ1ZyBlZmZlY3QgaGVhdG1hcHMgVFRMPVxcLFRUTCwgXFwucGRmXFwsIHNlcD1cXFxcKSwgd2lkdGggPSAxMiwgaGVpZ2h0ID0gNilcbmZvciAodGFyZ2V0X2RydWcgaW4gdW5pcXVlKGZpbmFsLm1vZGVsJGRydWcpKXtcbiAgcGxvdF9waGVhdG1hcCh0YXJnZXRfZHJ1ZywgXG4gICAgICAgICAgICAgICAgY3JlYXRlLmRydWcuZWZmZWN0LmRhdGEuZnJhbWUoXG4gICAgICAgICAgICAgICAgICB0YXJnZXRfZHJ1ZyxcbiAgICAgICAgICAgICAgICAgIG5vcm1hbC5iZWhhdmlvci5wdmFsLnRocmVzaG9sZCwgXG4gICAgICAgICAgICAgICAgICBub3JtYWwuYmVoYXZpb3Iuc2xvcGUudGhyZXNob2xkLCBcbiAgICAgICAgICAgICAgICAgIGRydWcucHZhbC50aHJlc2hvbGQsIFxuICAgICAgICAgICAgICAgICAgZHJ1Zy5zbG9wZS50aHJlc2hvbGQsXG4gICAgICAgICAgICAgICAgICBUVEwsXG4gICAgICAgICAgICAgICAgICBmZWF0dXJlcy5vZi5pbnRlcmVzdCksXG4gICAgICAgICAgICAgICAgY2x1c3RlcmluZ19yb3dzLFxuICAgICAgICAgICAgICAgIGNsdXN0ZXJpbmdfY29scyxcbiAgICAgICAgICAgICAgICBkZW5kcm89RkFMU0UpXG59XG5kZXYub2ZmKClcbmBgYFxuYGBgIn0= -->

```r
```r
# Parameters for the heat map scores
TTL <- -84
normal.behavior.pval.threshold <- 1.
normal.behavior.slope.threshold <- 0.
drug.pval.threshold <- 1.
drug.slope.threshold <- 0.
features.of.interest <- names(top.feature.index)
ref.clustering.feature <- \Metformin\

# Building the clustering of reference for all the heatmaps
ref_data <- create.drug.effect.data.frame(
                  ref.clustering.feature,
                  normal.behavior.pval.threshold, 
                  normal.behavior.slope.threshold, 
                  drug.pval.threshold, 
                  drug.slope.threshold,
                  TTL,
                  features.of.interest)
data <- as.matrix(ref_data[, -1])
rownames(data) <- ref_data$population
data[is.na(data)] <- 0
clustering_rows <- hclust(dist(data))
clustering_cols <- hclust(dist(t(data)))


# Plotting all the heat maps
pdf(paste(drug_assay_path, \/plots/Drug effect heatmaps TTL=\,TTL, \.pdf\, sep=\\), width = 12, height = 6)
for (target_drug in unique(final.model$drug)){
  plot_pheatmap(target_drug, 
                create.drug.effect.data.frame(
                  target_drug,
                  normal.behavior.pval.threshold, 
                  normal.behavior.slope.threshold, 
                  drug.pval.threshold, 
                  drug.slope.threshold,
                  TTL,
                  features.of.interest),
                clustering_rows,
                clustering_cols,
                dendro=FALSE)
}
dev.off()

<!-- rnb-source-end -->

<!-- rnb-output-begin eyJkYXRhIjoibnVsbCBkZXZpY2UgXG4gICAgICAgICAgMSBcbiJ9 -->

null device 1




<!-- rnb-output-end -->

<!-- rnb-chunk-end -->


<!-- rnb-text-begin -->


### Global visualization : drug effects

Here we plot a figure helping us visualize the effect of one drug based on the slope of its linear model across all features.


<!-- rnb-text-end -->


<!-- rnb-chunk-begin -->


<!-- rnb-source-begin eyJkYXRhIjoiYGBgclxuYGBgclxuc2xvcGVfdGhyZXNob2xkIDwtIDJlLTEgIyBBYm92ZSB0aGlzIHRocmVzaG9sZCB0aGUgY29sb3Igb2YgdGhlIHBsb3Qgd2lsbCBiZSB0aGUgbW9zdCBpbnRlbnNlIG9uZVxucHZhbF90aHJlc2hvbGQgPC0gNWUtMiAjIFVuZGVyIHRoaXMgdGhyZXNob2xkIHRoZSBzaXplIG9mIHRoZSBub2RlIHdpbGwgYmUgdGhlIGJpZ2dlc3Qgb25lIChpZiB0YWtpbmcgcHZhbHVlIGZvciBzaXplKVxucm1zZV90aHJlc2hvbGQgPC0gMWUtMiAjIFVuZGVyIHRoaXMgdGhyZXNob2xkIHRoZSBzaXplIG9mIHRoZSBub2RlIHdpbGwgYmUgdGhlIGJpZ2dlc3Qgb25lIChpZiB0YWtpbmcgcm1zZSBmb3Igc2l6ZSlcbnByZWNpc2lvbiA8LSAwLiAjIFVuZGVyIHRoaXMgdGhyZXNob2xkIHRoZSB2YWx1ZXMgaW4gdGhlIGRhdGFzZXQgb24gd2hpY2ggdGhlIG1vZGVsIGlzIGJ1aWx0IGlzIG5vdCByZWxldmFudCAoU2xvcGVfaW50ZW5zaXR5IDwtIDApXG5cbmZpbmFsLm1vZGVsLmluZm8uZGVjb21wIDwtIGZpbmFsLm1vZGVsICU+JVxuICAgICAgICAgICAgICAgICAgICAgICAgZ3JvdXBfYnkoZmVhdHVyZSwgZHJ1ZykgJT4lXG4gICAgICAgICAgICAgICAgICAgICAgICBzbGljZSgxKSAlPiVcbiAgICAgICAgICAgICAgICAgICAgICAgIG11dGF0ZSgjIFJldHJpZXZpbmcgdGhlIHNlcGFyYXRpb24gOiBwb3B1bGF0aW9uLCByZWFnZW50LCBzdGltdWxhdGlvblxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBvcHVsYXRpb24gPSBzdWIoXFxeKC4qPylfLipcXCwgXFxcXFxcMVxcLCBhcy5jaGFyYWN0ZXIoZmVhdHVyZSkpLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlYWdlbnQgPSBzdWIoXFwuKj9fKC4qPylfLipcXCwgXFxcXFxcMVxcLCBhcy5jaGFyYWN0ZXIoZmVhdHVyZSkpLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN0aW11bGF0aW9uID0gc3ViKFxcLipfLipfKC4qKVxcLCBcXFxcXFwxXFwsIGFzLmNoYXJhY3RlcihmZWF0dXJlKSksXG5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIElmIHRoZSBhYnNvbHV0ZSB2YWx1ZSBvZiB0aGUgc2xvcGUgaXMgZ3JlYXRlciB0aGFuIHRoZSB0aHJlc2hvbGQsIFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgdGhlIHNsb3BlIGlzIHJlcGxhY2VkIGJ5IHRoZSB0aHJlc2hvbGQgKHdpdGggdGhlIGFkZXF1YXRlIHNpZ24pXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgU2xvcGUgPSBpZmVsc2Uoc2xvcGUgPiBzbG9wZV90aHJlc2hvbGQsIHNsb3BlX3RocmVzaG9sZCwgc2xvcGUpLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFNsb3BlID0gaWZlbHNlKHNsb3BlIDwgLXNsb3BlX3RocmVzaG9sZCwgLXNsb3BlX3RocmVzaG9sZCwgc2xvcGUpLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgSWYgdGhlIHB2YWx1ZSBpcyBzbWFsbGVyIHRoYW4gdGhlIHRocmVzaG9sZCwgXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyB0aGUgcHZhbHVlIGlzIHJlcGxhY2VkIGJ5IHRoZSB0aHJlc2hvbGRcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwdmFsID0gaWZlbHNlKHB2YWwgPCBwdmFsX3RocmVzaG9sZCwgcHZhbF90aHJlc2hvbGQsIHB2YWwpLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgbG9nIHRyYW5zZm9ybSBub3JtYWxpemVkIGJ5IHRoZSB0aHJlc2hvbGRcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsb2dfcHZhbCA9IGxvZzEwKHB2YWwpL2xvZzEwKHB2YWxfdGhyZXNob2xkKSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIElmIHRoZSBybXNlIGlzIHNtYWxsZXIgdGhhbiB0aGUgdGhyZXNob2xkLCBcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIHRoZSBybXNlIGlzIHJlcGxhY2VkIGJ5IHRoZSB0aHJlc2hvbGRcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBSTVNFID0gaWZlbHNlKHJtc2UgPCBybXNlX3RocmVzaG9sZCwgcm1zZV90aHJlc2hvbGQsIHJtc2UpLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgbG9nIHRyYW5zZm9ybSBub3JtYWxpemVkIGJ5IHRoZSB0aHJlc2hvbGRcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsb2dfUk1TRSA9IGxvZzEwKFJNU0UpL2xvZzEwKHJtc2VfdGhyZXNob2xkKSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIFNsb3BlX2ludGVuc2l0eSA9IFNsb3BlLyhtYXgoc3Vic2V0IGRhdGEpIC0gbWluKHN1YnNldCBkYXRhKSkgb25seSB3aGVuIHRoZSBtZWFzdXJlcyBhcmUgc2lnbmlmaWNhbnRcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYXhfdmFsID0gbWF4KEFsbFBlbkRvc2VyZXNwb25zZVtBbGxQZW5Eb3NlcmVzcG9uc2UkZHJ1ZyA9PSBkcnVnICYgXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBBbGxQZW5Eb3NlcmVzcG9uc2UkZmVhdHVyZSA9PSBmZWF0dXJlLF0kdmFsdWUpLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1pbl92YWwgPSBtaW4oQWxsUGVuRG9zZXJlc3BvbnNlW0FsbFBlbkRvc2VyZXNwb25zZSRkcnVnID09IGRydWcgJiBcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEFsbFBlbkRvc2VyZXNwb25zZSRmZWF0dXJlID09IGZlYXR1cmUsXSR2YWx1ZSksXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgU2xvcGVfaW50ZW5zaXR5ID0gaWZlbHNlKG1heF92YWwgLSBtaW5fdmFsIDwgcHJlY2lzaW9uLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAwLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBTbG9wZS8obWF4X3ZhbCAtIG1pbl92YWwpKSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIENvb3JkaW5hdGVzIGZvciB0aGUgcGxvdCBvZiB0aGUgcmVhZ2VudHNcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIyBTVEFUIGZpcnN0IGNvbHVtblxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHggPSBpZmVsc2UoZ3JlcGwoXFxTVEFUXFwsIHJlYWdlbnQpLCAxLjUsIDApLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMjIFNUQVQxICgxLDQpXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeSA9IGlmZWxzZShyZWFnZW50ID09IFxcU1RBVDFcXCwgNCwgMCksXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyMgU1RBVDMgKDEsMylcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5ID0gaWZlbHNlKHJlYWdlbnQgPT0gXFxTVEFUM1xcLCAzLCB5KSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIyBTVEFUNSAoMSwyKVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHkgPSBpZmVsc2UocmVhZ2VudCA9PSBcXFNUQVQ1XFwsIDIsIHkpLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMjIFNUQVQ2ICgxLDEpXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeSA9IGlmZWxzZShyZWFnZW50ID09IFxcU1RBVDZcXCwgMSwgeSksXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyMgTkZrQiAoMyw0KVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHggPSBpZmVsc2UocmVhZ2VudCA9PSBcXE5Ga0JcXCwgMywgeCksXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeSA9IGlmZWxzZShyZWFnZW50ID09IFxcTkZrQlxcLCA0LCB5KSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIyBFUksgKDMsMylcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB4ID0gaWZlbHNlKHJlYWdlbnQgPT0gXFxFUktcXCwgMywgeCksXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeSA9IGlmZWxzZShyZWFnZW50ID09IFxcRVJLXFwsIDMsIHkpLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMjIFM2ICgzLDIpXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeCA9IGlmZWxzZShyZWFnZW50ID09IFxcUzZcXCwgMywgeCksXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeSA9IGlmZWxzZShyZWFnZW50ID09IFxcUzZcXCwgMiwgeSksXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyMgTUFQS0FQSzIgKDMsMSlcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB4ID0gaWZlbHNlKHJlYWdlbnQgPT0gXFxNQVBLQVBLMlxcLCAzLCB4KSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5ID0gaWZlbHNlKHJlYWdlbnQgPT0gXFxNQVBLQVBLMlxcLCAxLCB5KSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIyBJa0IgKDQsNClcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB4ID0gaWZlbHNlKHJlYWdlbnQgPT0gXFxJa0JcXCwgNCwgeCksXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeSA9IGlmZWxzZShyZWFnZW50ID09IFxcSWtCXFwsIDQsIHkpLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMjIENSRUIgKDQsMylcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB4ID0gaWZlbHNlKHJlYWdlbnQgPT0gXFxDUkVCXFwsIDQsIHgpLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHkgPSBpZmVsc2UocmVhZ2VudCA9PSBcXENSRUJcXCwgMywgeSksXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyMgcDM4ICg0LDIpXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeCA9IGlmZWxzZShyZWFnZW50ID09IFxccDM4XFwsIDQsIHgpLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHkgPSBpZmVsc2UocmVhZ2VudCA9PSBcXHAzOFxcLCAyLCB5KSlcbmBgYFxuYGBgIn0= -->

```r
```r
slope_threshold <- 2e-1 # Above this threshold the color of the plot will be the most intense one
pval_threshold <- 5e-2 # Under this threshold the size of the node will be the biggest one (if taking pvalue for size)
rmse_threshold <- 1e-2 # Under this threshold the size of the node will be the biggest one (if taking rmse for size)
precision <- 0. # Under this threshold the values in the dataset on which the model is built is not relevant (Slope_intensity <- 0)

final.model.info.decomp <- final.model %>%
                        group_by(feature, drug) %>%
                        slice(1) %>%
                        mutate(# Retrieving the separation : population, reagent, stimulation
                               population = sub(\^(.*?)_.*\, \\\1\, as.character(feature)),
                               reagent = sub(\.*?_(.*?)_.*\, \\\1\, as.character(feature)),
                               stimulation = sub(\.*_.*_(.*)\, \\\1\, as.character(feature)),

                               # If the absolute value of the slope is greater than the threshold, 
                               # the slope is replaced by the threshold (with the adequate sign)
                               Slope = ifelse(slope > slope_threshold, slope_threshold, slope),
                               Slope = ifelse(slope < -slope_threshold, -slope_threshold, slope),
                               # If the pvalue is smaller than the threshold, 
                               # the pvalue is replaced by the threshold
                               pval = ifelse(pval < pval_threshold, pval_threshold, pval),
                               # log transform normalized by the threshold
                               log_pval = log10(pval)/log10(pval_threshold),
                               # If the rmse is smaller than the threshold, 
                               # the rmse is replaced by the threshold
                               RMSE = ifelse(rmse < rmse_threshold, rmse_threshold, rmse),
                               # log transform normalized by the threshold
                               log_RMSE = log10(RMSE)/log10(rmse_threshold),
                               # Slope_intensity = Slope/(max(subset data) - min(subset data)) only when the measures are significant
                               max_val = max(AllPenDoseresponse[AllPenDoseresponse$drug == drug & 
                                                                  AllPenDoseresponse$feature == feature,]$value),
                               min_val = min(AllPenDoseresponse[AllPenDoseresponse$drug == drug & 
                                                                  AllPenDoseresponse$feature == feature,]$value),
                               Slope_intensity = ifelse(max_val - min_val < precision,
                                                        0,
                                                        Slope/(max_val - min_val)),
                               
                               # Coordinates for the plot of the reagents
                               ## STAT first column
                               x = ifelse(grepl(\STAT\, reagent), 1.5, 0),
                               ## STAT1 (1,4)
                               y = ifelse(reagent == \STAT1\, 4, 0),
                               ## STAT3 (1,3)
                               y = ifelse(reagent == \STAT3\, 3, y),
                               ## STAT5 (1,2)
                               y = ifelse(reagent == \STAT5\, 2, y),
                               ## STAT6 (1,1)
                               y = ifelse(reagent == \STAT6\, 1, y),
                               ## NFkB (3,4)
                               x = ifelse(reagent == \NFkB\, 3, x),
                               y = ifelse(reagent == \NFkB\, 4, y),
                               ## ERK (3,3)
                               x = ifelse(reagent == \ERK\, 3, x),
                               y = ifelse(reagent == \ERK\, 3, y),
                               ## S6 (3,2)
                               x = ifelse(reagent == \S6\, 3, x),
                               y = ifelse(reagent == \S6\, 2, y),
                               ## MAPKAPK2 (3,1)
                               x = ifelse(reagent == \MAPKAPK2\, 3, x),
                               y = ifelse(reagent == \MAPKAPK2\, 1, y),
                               ## IkB (4,4)
                               x = ifelse(reagent == \IkB\, 4, x),
                               y = ifelse(reagent == \IkB\, 4, y),
                               ## CREB (4,3)
                               x = ifelse(reagent == \CREB\, 4, x),
                               y = ifelse(reagent == \CREB\, 3, y),
                               ## p38 (4,2)
                               x = ifelse(reagent == \p38\, 4, x),
                               y = ifelse(reagent == \p38\, 2, y))

<!-- rnb-source-end -->

<!-- rnb-chunk-end -->


<!-- rnb-text-begin -->


Here we are doing one of the 100 plots that are going to be built for each drug so that we can plot the legend as well. Each node represent a reagent, its size is proportional to $-log_{10}(p_{val})$, its color is 


<!-- rnb-text-end -->


<!-- rnb-chunk-begin -->


<!-- rnb-source-begin eyJkYXRhIjoiYGBgclxuYGBgclxuIyBFeGFtcGxlIG9mIHNldHRpbmdzIGZvciB0aGUgcGxvdFxuZXhhbXBsZV9kcnVnIDwtIFxcRm9saWMgYWNpZFxcXG5leGFtcGxlX3BvcHVsYXRpb24gPC0gXFxDRDRUZW1cXFxuZXhhbXBsZV9zdGltdWxhdGlvbiA8LSBcXElGTmFcXFxuXG4jIFN1YnNldFxuZGYgPC0gZmluYWwubW9kZWwuaW5mby5kZWNvbXBbZmluYWwubW9kZWwuaW5mby5kZWNvbXAkZHJ1ZyA9PSBleGFtcGxlX2RydWcgJiBcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmluYWwubW9kZWwuaW5mby5kZWNvbXAkcG9wdWxhdGlvbiA9PSBleGFtcGxlX3BvcHVsYXRpb24gJlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmaW5hbC5tb2RlbC5pbmZvLmRlY29tcCRzdGltdWxhdGlvbiA9PSBleGFtcGxlX3N0aW11bGF0aW9uLF1cblxuIyBQbG90XG5wIDwtIGdncGxvdChkZiwgYWVzKHggPSB4LCB5ID0geSkpICtcbiAgIyBOb2RlcyBzaXplLCBib3JkZXIgYW5kIGNvbG9yXG4gIGdlb21fcG9pbnQoYWVzKHNpemUgPSBsb2dfcHZhbCwgZmlsbCA9IFNsb3BlX2ludGVuc2l0eSksIHNoYXBlID0gMjEpICtcbiAgIyBOYW1lIG9mIHRoZSBub2Rlc1xuICBnZW9tX3RleHQoYWVzKGxhYmVsID0gcmVhZ2VudCksIHZqdXN0ID0gLTEuNSwgaGp1c3QgPSAwLjUsIHNpemUgPSA1LCBjb2xvciA9IFxcYmxhY2tcXCkgK1xuICAjIFNjYWxlIG9mIHRoZSBzaXplIG9mIHRoZSBub2Rlc1xuICBzY2FsZV9zaXplX2NvbnRpbnVvdXMocmFuZ2UgPSBjKDIsIDEwKSwgbGltaXRzID0gYygwLCAxKSkgK1xuICAjIFNjYWxlIG9mIHRoZSBjb2xvciBvZiB0aGUgbm9kZXNcbiAgc2NhbGVfZmlsbF9ncmFkaWVudDIobG93ID0gXFxibHVlXFwsIG1pZCA9IFxcd2hpdGVcXCwgaGlnaCA9IFxccmVkXFwsIG1pZHBvaW50ID0gMCwgbGltaXRzID0gYygtMC4zLCAwLjMpKSArXG4gICMgTGVnZW5kIHNldHRpbmdzIChwb3NpdGlvbiBhbmQgYmFja2dyb3VuZClcbiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gXFxib3R0b21cXCwgbGVnZW5kLmJveCA9IFxcaG9yaXpvbnRhbFxcLCBsZWdlbmQua2V5ID0gZWxlbWVudF9ibGFuaygpKSArXG4gICMgQXhpc1xuICBzY2FsZV94X2NvbnRpbnVvdXMobGltaXRzID0gYygwLjUsIDUpLCBleHBhbmQgPSBjKDAsIDApKSArICAjIFNldCB4LWF4aXMgbGltaXRzIGFuZCByZW1vdmUgZXhwYW5zaW9uXG4gIHNjYWxlX3lfY29udGludW91cyhsaW1pdHMgPSBjKDAuNSwgNC41KSwgZXhwYW5kID0gYygwLiwgMC4pKSArXG4gICMgTGFibGVzXG4gIGxhYnMoeCA9IE5VTEwsIHkgPSBOVUxMLCBzaXplID0gXFxsb2dfcHZhbFxcLCBmaWxsID0gXFxTbG9wZV9pbnRlbnNpdHlcXCwgY29sb3IgPSBcXENsYXNzXFwpXG5cbiMgU2F2aW5nIHRoZSBwbG90XG5nZ3NhdmUocGFzdGUwKGRydWdfYXNzYXlfcGF0aCwgXFwvcGxvdHMvbGVnZW5kX2dyaWRfZWZmZWN0X3Bsb3QucG5nXFwpLCBwbG90ID0gcCwgd2lkdGggPSAxMCwgaGVpZ2h0ID0gOClcbmBgYFxuYGBgIn0= -->

```r
```r
# Example of settings for the plot
example_drug <- \Folic acid\
example_population <- \CD4Tem\
example_stimulation <- \IFNa\

# Subset
df <- final.model.info.decomp[final.model.info.decomp$drug == example_drug & 
                                   final.model.info.decomp$population == example_population &
                                   final.model.info.decomp$stimulation == example_stimulation,]

# Plot
p <- ggplot(df, aes(x = x, y = y)) +
  # Nodes size, border and color
  geom_point(aes(size = log_pval, fill = Slope_intensity), shape = 21) +
  # Name of the nodes
  geom_text(aes(label = reagent), vjust = -1.5, hjust = 0.5, size = 5, color = \black\) +
  # Scale of the size of the nodes
  scale_size_continuous(range = c(2, 10), limits = c(0, 1)) +
  # Scale of the color of the nodes
  scale_fill_gradient2(low = \blue\, mid = \white\, high = \red\, midpoint = 0, limits = c(-0.3, 0.3)) +
  # Legend settings (position and background)
  theme(legend.position = \bottom\, legend.box = \horizontal\, legend.key = element_blank()) +
  # Axis
  scale_x_continuous(limits = c(0.5, 5), expand = c(0, 0)) +  # Set x-axis limits and remove expansion
  scale_y_continuous(limits = c(0.5, 4.5), expand = c(0., 0.)) +
  # Lables
  labs(x = NULL, y = NULL, size = \log_pval\, fill = \Slope_intensity\, color = \Class\)

# Saving the plot
ggsave(paste0(drug_assay_path, \/plots/legend_grid_effect_plot.png\), plot = p, width = 10, height = 8)

<!-- rnb-source-end -->

<!-- rnb-chunk-end -->


<!-- rnb-text-begin -->


Plotting a grid composed of subplots like the one above for every population and avery stimulation and each drug


<!-- rnb-text-end -->


<!-- rnb-chunk-begin -->


<!-- rnb-source-begin eyJkYXRhIjoiYGBgclxuYGBgclxuIyBVc2VmdWwgdmFyaWFibGVzICh3ZSByZXdyaXRlIHRoZW0gYmVjYXVzZSB0aGUgb3JkZXIgaXMgaW1wb3J0YW50IGZvciB0aGUgZmlndXJlcylcbnN0aW11bGF0aW9ucyA8LSBjKFxcR01DU0ZcXCwgXFxJRk5hXFwsIFxcSUwyNDZcXCwgXFxMUFNcXCwgXFx1bnN0aW1cXClcbnBvcHVsYXRpb25zIDwtIGMoXFxCY2VsbHNcXCwgXFxDRDRUY21cXCwgXFxDRDRUZWZmXFwsIFxcQ0Q0VGVtXFwsIFxcQ0Q0VG5haXZlXFwsIFxcQ0Q0bmVnQ0Q4bmVnVGNlbGxzXFwsIFxcQ0Q1NmhpQ0QxNm5lZ05LXFwsIFxcQ0Q1NmxvQ0QxNnBvc05LXFwsIFxcQ0Q4VGNtXFwsIFxcQ0Q4VGVmZlxcLCBcXENEOFRlbVxcLCBcXENEOFRuYWl2ZVxcLCBcXEdyYW51bG9jeXRlc1xcLCBcXE1EU0NzXFwsIFxcTktUXFwsIFxcVHJlZ3NcXCwgXFxpbnRNQ3NcXCwgXFxtRENzXFwsIFxcbmNNQ3NcXCwgXFxwRENzXFwpXG5EcnVncyA8LSBjKFxcQ2Vmb3RheGltZVxcLCBcXExhbnNvcHJhem9sZVxcLCBcXElvcGFtaWRvbFxcLCBcXElvaGV4b2xcXCwgXFxCZW56eWxwZW5pY2lsbGluXFwsIFxcQ2hsb3J0aGFsaWRvbmVcXCwgXFxSaWZhYnV0aW5cXCwgXFxJb2RpeGFub2xcXCwgXFxNZXRmb3JtaW5cXCwgXFxGb2xpYyBhY2lkXFwsIFxcQ2xvdHJpbWF6b2xlXFwsIFxcTWFwcm90aWxpbmVcXCwgXFxQcm9nZXN0ZXJvbmVcXCwgXFxQcmF2YXN0YXRpblxcLCBcXE1ldGh5bHByZWRvbmlzb2xvbmVcXClcbmZlYXR1cmVzLm9mLmludGVyZXN0IDwtIG5hbWVzKHRvcC5mZWF0dXJlLmluZGV4KVxuICBcbnBsb3RfZHJ1Z19ncmlkX2VmZmVjdCA8LSBmdW5jdGlvbih0YXJnZXRfZHJ1ZywgZmVhdHVyZXMub2YuaW50ZXJlc3Qpe1xuICBwbG90X2xpc3QgPC0gbGlzdCgpXG4gICMgSXRlcmF0ZSBvdmVyIHRoZSByb3dzIGFuZCBjb2x1bW5zIHRvIGNyZWF0ZSB0aGUgcGxvdHNcbiAgcG9wX3RpdGxlIDwtIFRSVUVcbiAgZm9yIChzdGltIGluIHN0aW11bGF0aW9ucykge1xuICAgIHN0aW1fdGl0bGUgPC0gVFJVRVxuICAgIGZvciAocG9wdWxhdGlvbiBpbiBwb3B1bGF0aW9ucykge1xuICAgICAgIyBGaWx0ZXIgdGhlIGRhdGEgZm9yIHRoZSBjdXJyZW50IHBvcHVsYXRpb24gYW5kIHN0aW11bGF0aW9uXG4gICAgICBzdWJzZXRfZGYgPC0gZmluYWwubW9kZWwuaW5mby5kZWNvbXBbZmluYWwubW9kZWwuaW5mby5kZWNvbXAkZHJ1ZyA9PSB0YXJnZXRfZHJ1ZyAmXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmaW5hbC5tb2RlbC5pbmZvLmRlY29tcCRwb3B1bGF0aW9uID09IHBvcHVsYXRpb24gJlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmluYWwubW9kZWwuaW5mby5kZWNvbXAkc3RpbXVsYXRpb249PXN0aW0sXSAlPiVcbiAgICAgICAgICAgICAgICAgICAgbXV0YXRlKG9mLmludGVyZXN0ID0gaWZlbHNlKGZlYXR1cmUgJWluJSBmZWF0dXJlcy5vZi5pbnRlcmVzdCxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFxcWWVzXFwsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBcXE5vXFwpLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgYm9yZGVyLnRoaWNrbmVzcyA9IGlmZWxzZShmZWF0dXJlICVpbiUgZmVhdHVyZXMub2YuaW50ZXJlc3QsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDIuLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAxLikpXG4gICAgICBcbiAgICAgICMgU3VicGxvdCBmb3IgdGhlIGN1cnJlbnQgcG9wdWxhdGlvbiBhbmQgc3RpbXVsYXRpb25cbiAgICAgIHAgPC0gZ2dwbG90KHN1YnNldF9kZiwgYWVzKHggPSB4LzI1LCB5ID0geS8yNSwgY29sb3I9b2YuaW50ZXJlc3QsIHN0cm9rZT1ib3JkZXIudGhpY2tuZXNzKSkgK1xuICAgICAgICAjIE5vZGVzIHNpemUsIGJvcmRlciBhbmQgY29sb3JcbiAgICAgICAgZ2VvbV9wb2ludChhZXMoc2l6ZSA9IGxvZ19wdmFsLCBmaWxsID0gU2xvcGVfaW50ZW5zaXR5LCBjb2xvcj1vZi5pbnRlcmVzdCwgc3Ryb2tlPWJvcmRlci50aGlja25lc3MpLCBzaGFwZSA9IDIxKSArXG4gICAgICAgICMgU2NhbGUgb2YgdGhlIHNpemUgb2YgdGhlIG5vZGVzXG4gICAgICAgIHNjYWxlX3NpemVfY29udGludW91cyhyYW5nZSA9IGMoMiwgMTApLCBsaW1pdHMgPSBjKDAsIDEpKSArXG4gICAgICAgICMgU2NhbGUgb2YgdGhlIGNvbG9yIG9mIHRoZSBub2Rlc1xuICAgICAgICBzY2FsZV9maWxsX2dyYWRpZW50Mihsb3cgPSBcXGJsdWVcXCwgbWlkID0gXFx3aGl0ZVxcLCBoaWdoID0gXFxyZWRcXCwgbWlkcG9pbnQgPSAwLCBsaW1pdHMgPSBjKC0wLjMsIDAuMykpICtcbiAgICAgICAgIyBCb3JkZXIgb2YgdGhlIG5vZGVzXG4gICAgICAgIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjKFxcWWVzXFwgPSBcXHJlZFxcKSkgK1xuICAgICAgICAjIEFkZGluZyBhIGJvcmRlciB0byB0aGUgZmlndXJlIGlmIHRoZXJlIGFyZSBmZWF0dXJlcyBvZiBpbnRlcmVzdCBpbnNpZGVcbiAgICAgICAgZ2VvbV9yZWN0KGFlcyh4bWluID0gMC4wMiwgeG1heCA9IDAuMiwgeW1pbiA9IDAuLCB5bWF4ID0gMC4yKSxcbiAgICAgICAgICAgICAgICAgIGZpbGwgPSBOQSxcbiAgICAgICAgICAgICAgICAgIGNvbG9yID0gXFxyZWRcXCxcbiAgICAgICAgICAgICAgICAgIGxpbmV0eXBlID0gXFxzb2xpZFxcLFxuICAgICAgICAgICAgICAgICAgc2l6ZSA9IGlmZWxzZShhbnkoc3Vic2V0X2RmJG9mLmludGVyZXN0ID09IFxcWWVzXFwpLCAxLjUsIE5BKSkgK1xuICAgICAgICAjIFJlbW92aW5nIGxlZ2VuZHMgYW5kIGFkanVzdGluZyBzaXplIGFuZCBtYXJnaW5zXG4gICAgICAgIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9IFxcbm9uZVxcLFxuICAgICAgICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDYsIG1hcmdpbiA9IG1hcmdpbihyID0gMCkpLFxuICAgICAgICAgIHBsb3QubWFyZ2luID0gbWFyZ2luKDAuNSwgMC4sIDAuLCAwLjUpLFxuICAgICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF9ibGFuaygpLFxuICAgICAgICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF9ibGFuaygpLFxuICAgICAgICAgIGF4aXMudGlja3MueCA9IGVsZW1lbnRfYmxhbmsoKSxcbiAgICAgICAgICBheGlzLnRpY2tzLnkgPSBlbGVtZW50X2JsYW5rKCksXG4gICAgICAgICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF90ZXh0KHNpemUgPSA2LCBtYXJnaW4gPSBtYXJnaW4ociA9IC0yKSksXG4gICAgICAgICAgYXhpcy50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSA2KSkgKyAgXG4gICAgICAgICMgTGFiZWxzICh5IGxhYmVsIG9ubHkgYXBwZWFyIGZvciB0aGUgZmlyc3QgY29sdW1uIG9mIHN1YnBsb3Qgd2l0aCB0aGUgbmFtZSBvZiB0aGUgc3RpbSlcbiAgICAgICAgbGFicyh4ID0gTlVMTCwgeSA9IGlmZWxzZShzdGltX3RpdGxlLCBzdGltLCBcXFxcKSwgc2l6ZSA9IFxcbG9nX3B2YWxcXCwgZmlsbCA9IFxcU2xvcGVfaW50ZW5zaXR5XFwsIGNvbG9yID0gXFxDbGFzc1xcKSArXG4gICAgICAgICMgQXhpc1xuICAgICAgICBzY2FsZV94X2NvbnRpbnVvdXMobGltaXRzID0gYygwLjAyLCAwLjIpLCBleHBhbmQgPSBjKDAsIDApKSArXG4gICAgICAgIHNjYWxlX3lfY29udGludW91cyhsaW1pdHMgPSBjKDAuLCAwLjIpLCBleHBhbmQgPSBjKDAuLCAwLikpICtcbiAgICAgICAgIyBUaXRsZSAob25seSBhcHBlYXIgZm9yIHRoZSBmaXJzdCByb3cgb2Ygc3VicGxvdHMgd2l0aCB0aGUgbmFtZSBvZiB0aGUgcG9wdWxhdGlvbilcbiAgICAgICAgZ2d0aXRsZShpZmVsc2UocG9wX3RpdGxlLCBwb3B1bGF0aW9uLCBcXFxcKSkgK1xuICAgICAgICAjIFJlbW92aW5nXG4gICAgICAgIGd1aWRlcyhmaWxsID0gXFxub25lXFwsIGNvbG9yID0gXFxub25lXFwsIHNpemUgPSBcXG5vbmVcXClcbiAgICAgIFxuICAgICAgIyBTdG9yZSB0aGUgcGxvdCBpbiB0aGUgcGxvdCBsaXN0XG4gICAgICBwbG90X2xpc3RbW2xlbmd0aChwbG90X2xpc3QpICsgMV1dIDwtIHBcbiAgICAgIHN0aW1fdGl0bGUgPC0gRkFMU0VcbiAgICB9XG4gICAgcG9wX3RpdGxlIDwtIEZBTFNFXG4gIH1cbiAgXG4gICMgQ3JlYXRpbmcgdGhlIGdyaWQgcGxvdFxuICBncmlkX2FycmFuZ2UgPC0gZ3JpZC5hcnJhbmdlKGdyb2JzID0gcGxvdF9saXN0LFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5jb2wgPSBsZW5ndGgocG9wdWxhdGlvbnMpLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5yb3cgPSBsZW5ndGgoc3RpbXVsYXRpb25zKSlcbiAgIyBBZGRpbmcgYSB0aXRsZSB0byB0aGUgZ3JpZCBwbG90XG4gIHRpdGxlIDwtIHRleHRHcm9iKHRhcmdldF9kcnVnLCBncCA9IGdwYXIoZm9udHNpemUgPSAxNiwgZm9udGZhY2UgPSBcXGJvbGRcXCkpXG4gIGxheW91dCA8LSByYmluZChjKDEpLCBjKDIpKVxuICBhcnJhbmdlZF9wbG90cyA8LSBhcnJhbmdlR3JvYih0aXRsZSwgZ3JpZF9hcnJhbmdlLCBsYXlvdXRfbWF0cml4ID0gbGF5b3V0LCBoZWlnaHRzID0gYygxLCA5KSlcbiAgXG4gIHJldHVybihhcnJhbmdlZF9wbG90cylcbn1cblxuIyBDcmVhdGluZyBhbmQgc2F2aW5nIHRoZSBmaWd1cmVzIGluIHBkZiBmaWxlc1xuZm9yICh0YXJnZXRfZHJ1ZyBpbiBEcnVncykge1xuICBncmlkX3Bsb3QgPC0gcGxvdF9kcnVnX2dyaWRfZWZmZWN0KHRhcmdldF9kcnVnLCBmZWF0dXJlcy5vZi5pbnRlcmVzdClcbiAgcGRmKHBhc3RlKGRydWdfYXNzYXlfcGF0aCwgXFwvcGxvdHMvXFwsIHRhcmdldF9kcnVnLCBcXF9ncmlkX2VmZmVjdF9wbG90cy5wZGZcXCwgc2VwPVxcXFwpLCB3aWR0aD0yMCwgaGVpZ2h0PTgpXG4gIGdyaWQuZHJhdyhncmlkX3Bsb3QpXG4gIGRldi5vZmYoKVxufVxuYGBgXG5gYGAifQ== -->

```r
```r
# Useful variables (we rewrite them because the order is important for the figures)
stimulations <- c(\GMCSF\, \IFNa\, \IL246\, \LPS\, \unstim\)
populations <- c(\Bcells\, \CD4Tcm\, \CD4Teff\, \CD4Tem\, \CD4Tnaive\, \CD4negCD8negTcells\, \CD56hiCD16negNK\, \CD56loCD16posNK\, \CD8Tcm\, \CD8Teff\, \CD8Tem\, \CD8Tnaive\, \Granulocytes\, \MDSCs\, \NKT\, \Tregs\, \intMCs\, \mDCs\, \ncMCs\, \pDCs\)
Drugs <- c(\Cefotaxime\, \Lansoprazole\, \Iopamidol\, \Iohexol\, \Benzylpenicillin\, \Chlorthalidone\, \Rifabutin\, \Iodixanol\, \Metformin\, \Folic acid\, \Clotrimazole\, \Maprotiline\, \Progesterone\, \Pravastatin\, \Methylpredonisolone\)
features.of.interest <- names(top.feature.index)
  
plot_drug_grid_effect <- function(target_drug, features.of.interest){
  plot_list <- list()
  # Iterate over the rows and columns to create the plots
  pop_title <- TRUE
  for (stim in stimulations) {
    stim_title <- TRUE
    for (population in populations) {
      # Filter the data for the current population and stimulation
      subset_df <- final.model.info.decomp[final.model.info.decomp$drug == target_drug &
                                             final.model.info.decomp$population == population &
                                             final.model.info.decomp$stimulation==stim,] %>%
                    mutate(of.interest = ifelse(feature %in% features.of.interest,
                                                \Yes\,
                                                \No\),
                           border.thickness = ifelse(feature %in% features.of.interest,
                                                     2.,
                                                     1.))
      
      # Subplot for the current population and stimulation
      p <- ggplot(subset_df, aes(x = x/25, y = y/25, color=of.interest, stroke=border.thickness)) +
        # Nodes size, border and color
        geom_point(aes(size = log_pval, fill = Slope_intensity, color=of.interest, stroke=border.thickness), shape = 21) +
        # Scale of the size of the nodes
        scale_size_continuous(range = c(2, 10), limits = c(0, 1)) +
        # Scale of the color of the nodes
        scale_fill_gradient2(low = \blue\, mid = \white\, high = \red\, midpoint = 0, limits = c(-0.3, 0.3)) +
        # Border of the nodes
        scale_color_manual(values = c(\Yes\ = \red\)) +
        # Adding a border to the figure if there are features of interest inside
        geom_rect(aes(xmin = 0.02, xmax = 0.2, ymin = 0., ymax = 0.2),
                  fill = NA,
                  color = \red\,
                  linetype = \solid\,
                  size = ifelse(any(subset_df$of.interest == \Yes\), 1.5, NA)) +
        # Removing legends and adjusting size and margins
        theme(legend.position = \none\,
          plot.title = element_text(size = 6, margin = margin(r = 0)),
          plot.margin = margin(0.5, 0., 0., 0.5),
          axis.text.x = element_blank(),
          axis.text.y = element_blank(),
          axis.ticks.x = element_blank(),
          axis.ticks.y = element_blank(),
          axis.title.y = element_text(size = 6, margin = margin(r = -2)),
          axis.text = element_text(size = 6)) +  
        # Labels (y label only appear for the first column of subplot with the name of the stim)
        labs(x = NULL, y = ifelse(stim_title, stim, \\), size = \log_pval\, fill = \Slope_intensity\, color = \Class\) +
        # Axis
        scale_x_continuous(limits = c(0.02, 0.2), expand = c(0, 0)) +
        scale_y_continuous(limits = c(0., 0.2), expand = c(0., 0.)) +
        # Title (only appear for the first row of subplots with the name of the population)
        ggtitle(ifelse(pop_title, population, \\)) +
        # Removing
        guides(fill = \none\, color = \none\, size = \none\)
      
      # Store the plot in the plot list
      plot_list[[length(plot_list) + 1]] <- p
      stim_title <- FALSE
    }
    pop_title <- FALSE
  }
  
  # Creating the grid plot
  grid_arrange <- grid.arrange(grobs = plot_list,
                               ncol = length(populations),
                               nrow = length(stimulations))
  # Adding a title to the grid plot
  title <- textGrob(target_drug, gp = gpar(fontsize = 16, fontface = \bold\))
  layout <- rbind(c(1), c(2))
  arranged_plots <- arrangeGrob(title, grid_arrange, layout_matrix = layout, heights = c(1, 9))
  
  return(arranged_plots)
}

# Creating and saving the figures in pdf files
for (target_drug in Drugs) {
  grid_plot <- plot_drug_grid_effect(target_drug, features.of.interest)
  pdf(paste(drug_assay_path, \/plots/\, target_drug, \_grid_effect_plots.pdf\, sep=\\), width=20, height=8)
  grid.draw(grid_plot)
  dev.off()
}

```

LS0tCnRpdGxlOiAiRHJ1ZyBhc3NheSBzY29yZXMgYW5kIHZpc3VhbGl6YXRpb24iCm91dHB1dDogaHRtbF9ub3RlYm9vawotLS0KCiMjIFBhdGhzCgoqKkNvcHkgUGFzdGUgSGVyZSB0aGUgcGF0aCB0byB5b3VyIERydWctQXNzYXktU3R1ZHkgZm9sZGVyKioKCmBgYHtyfQpteV9wYXRoPC0iL1VzZXJzL2pvbmFzYW1hci9EZXNrdG9wL0RydWctQXNzYXktU3R1ZHkiCmBgYAoKYGBge3J9CnNldHdkKHBhc3RlMChteV9wYXRoLCIvUnNjcmlwdHMiKSkKT09MX3BhdGg9cGFzdGUwKG15X3BhdGgsIi9PbnNldCBvZiBMYWJvciBjc3YiKQpkcnVnX2Fzc2F5X3BhdGg9cGFzdGUwKG15X3BhdGgsIi9EcnVnIGFzc2F5IGNzdiIpCmBgYAoKIyMgTGlicmFyaWVzCgpgYGB7cn0KbGlicmFyeSh0aWR5dmVyc2UpCmxpYnJhcnkodGlkeXNlbGVjdCkKbGlicmFyeShyZXNoYXBlMikKbGlicmFyeShkcGx5cikKbGlicmFyeShwaGVhdG1hcCkKbGlicmFyeShSQ29sb3JCcmV3ZXIpCmxpYnJhcnkodmlyaWRpcykKbGlicmFyeShwYWxldHRlZXIpCmxpYnJhcnkodGlkeXIpCmxpYnJhcnkoamFuaXRvcikKbGlicmFyeShsbWU0KQpsaWJyYXJ5KGxtZXJUZXN0KQpsaWJyYXJ5KHV0aWxzKQpsaWJyYXJ5KGdncGxvdDIpCmxpYnJhcnkocjJnbG1tKQpsaWJyYXJ5KHNqc3RhdHMpCmxpYnJhcnkoZ3JpZEV4dHJhKQpsaWJyYXJ5KGdyaWQpCmBgYAoKIyMgTG9hZGluZyBEYXRhIGFuZCBNb2RlbHMKCioqT09MIGRhdGEgYW5kIG1vZGVscyoqCgpgYGB7cn0KIyBkZl9tb2RlbApsb2FkKHBhc3RlMChPT0xfcGF0aCwgIi9wZW5fbW9kZWxfY3VydmVzX2N5dG9mLnJkYSIpKQojIGN1cnZlLmNsYXNzaWZpY2F0aW9uIDwtIGRmX3N1bQpjdXJ2ZS5jbGFzc2lmaWNhdGlvbiA8LSByZWFkLmNzdihwYXN0ZTAoT09MX3BhdGgsICIvcGVuX2NsYXNzaWZpY2F0aW9uX2N1cnZlc19jeXRvZi5jc3YiKSkKIyBwZW5hbGl6ZWQgZGF0YXNldCB3aXRoIG91dGNvbWVzIChET1MpIGFudGUgcGFydHVtCk9PTF9kYXRhIDwtIHJlYWQuY3N2KHBhc3RlMChPT0xfcGF0aCwgIi9pbW11bm9tZV9ub0VHQV9ET1NfcGVuX09PTC5jc3YiKSkgJT4lICAgCiAgICAgICAgICAgIGZpbHRlcihET1MgPD0gMCkgIyB3ZSBvbmx5IGFyZSBpbnRlcmVzdGVkIGluIERPUyA8PTAKIyBvdXRjb21lcwpET1MgPC0gT09MX2RhdGEkRE9TCiMgcmVzdWx0cyBmcm9tIHVuaXZhcmlhdGUgYW5hbHlzaXMgb24gT09MIGRhdGEKc3BlYXJtYW5fY29yIDwtIHJlYWRfY3N2KHBhc3RlMChPT0xfcGF0aCwgIi9Vbml2YXJpYXRlIHJlZ2F0ZWQgT09ML1NwZWFybWFuQ29ycmVsYXRpb25zUHZhbC5jc3YiKSkKIyBmZWF0dXJlLmluZGV4CmxvYWQocGFzdGUwKE9PTF9wYXRoLCAiL2ZlYXR1cmVfaW5kZXgucmRhIikpCmBgYAoKKipEcnVnIEFzc2F5IGRhdGEgYW5kIG1vZGVscyoqCgpgYGB7cn0KIyBtb2RlbC5zY29yZXMKbG9hZChwYXN0ZTAoZHJ1Z19hc3NheV9wYXRoLCAiL21vZGVsIHNjb3Jlcy5yZGEiKSkKIyBwc2V1ZG9fbG9nMTAuaW5kaXZpZHVhbC5saW5lYXIubW9kZWwKbG9hZChwYXN0ZTAoZHJ1Z19hc3NheV9wYXRoLCAiL3BzZXVkb19sb2cxMCBtZWRpYW4gbGluZWFyIG1vZGVscy5yZGEiKSkKIyBwc2V1ZG9fbG9nMTAubWVkaWFuLmxpbmVhci5tb2RlbApsb2FkKHBhc3RlMChkcnVnX2Fzc2F5X3BhdGgsICIvcHNldWRvX2xvZzEwIGluZGl2aWR1YWwgbGluZWFyIG1vZGVscy5yZGEiKSkKIyBNZWRpYW5Eb3NlcmVwb25zZQpsb2FkKHBhc3RlMChkcnVnX2Fzc2F5X3BhdGgsICIvbWVkaWFuIHBlbiBkb3NlIHJlc3BvbnNlIHdpdGggc2NhbGVzLnJkYSIpKQojIEFsbFBlbkRvc2VyZXBvbnNlCmxvYWQocGFzdGUwKGRydWdfYXNzYXlfcGF0aCwgIi9hbGwgcGVuIGRvc2UgcmVzcG9uc2Ugd2l0aCBzY2FsZXMucmRhIikpCmBgYAoKIyMgU2NvcmVzCgpIZXJlIHdlIHdhbnQgdG8gY29tcGFyZSB0aGUgZHJ1ZyBlZmZlY3Qgb24gZWFjaCBmZWF0dXJlIHRvIHRoZSAibm9ybWFsIiBiZWhhdmlvciBvZiB0aGUgZmVhdHVyZSBtb2RlbGVkIGluIE9PTCBzdHVkeS4KCiMjIyBBdXhpbGlhcmllcyBzY29yZSBmdW5jdGlvbnMKCioqZHJ1Zy5lZmZlY3QqKgoKYGBge3J9CiMgRnVuY3Rpb24gd2hpY2ggcmV0dXJuOgojICsxIGZvciBhY3RpdmF0aW5nIGRydWdzCiMgLTEgZm9yIGluaGliaXRpbmcgZHJ1Z3MKIyAwIGZvciBub24gYWN0aXZlIChvciB1bmNlcnRhaW4pIGRydWdzCiMgYmFzZWQgb24gdGhlIHNsb3BlIG9mIHRoZSBtb2RlbCBhbmQgaXRzIHAtdmFsdWUKCmRydWcuZWZmZWN0IDwtIGZ1bmN0aW9uKHNsb3BlLCBwdmFsLCBzbG9wZS50aHJlc2hvbGQsIHB2YWwudGhyZXNob2xkKXsKICBpZiAoKGFicyhzbG9wZSkgPiBzbG9wZS50aHJlc2hvbGQpICYgKHB2YWwgPCBwdmFsLnRocmVzaG9sZCkgJiAoIWlzLm5hKHNsb3BlKSkgJiAoIWlzLm5hKHB2YWwpKSl7CiAgICByZXR1cm4oc2xvcGUvYWJzKHNsb3BlKSkKICB9CiAgZWxzZXsKICAgIHJldHVybigwKQogIH0KfQpgYGAKCioqZmVhdHVyZS5ub3JtYWwuYmVoYXZpb3IuYXQuVFRMKioKCmBgYHtyfQojIEZ1bmN0aW9uIHdoaWNoIHJldHVybnMKIyAxIGlmIHRoZSBtb2RlbCAob2YgdGhlIE9PTCBmZWF0dXJlKSBpcyBpbmNyZWFzaW5nIGF0IFRUTAojIC0xIGlmIHRoZSBtb2RlbCAob2YgdGhlIE9PTCBmZWF0dXJlKSBpcyBkZWNyZWFzaW5nIGF0IFRUTAojIE5BIGlmIHRoZSBiZWhhdmlvciBvZiB0aGUgZmVhdHVyZSBpcyBpbmNvbmNsdXNpdmUgKG1pc3NpbmcgbW9kZWwgb3IgdG9vIHdlYWsgc2xvcGUpCiMgYmFzZWQgb24gdGhlIG1vZGVsIChjb250YWluZWQgaW4gYSBsaXN0KSBpdHNlbGYgYW5kIGl0cyBwLXZhbHVlCgpmZWF0dXJlLm5vcm1hbC5iZWhhdmlvci5hdC5UVEwgPC0gZnVuY3Rpb24obW9kZWwsIHB2YWwsIHNsb3BlLnRocmVzaG9sZCwgcHZhbC50aHJlc2hvbGQsIFRUTCl7CiAgaWYgKGxlbmd0aChwdmFsKSA9PSAwIHx8IGlzLm5hKHB2YWwpIHx8cHZhbCA+IHB2YWwudGhyZXNob2xkIHx8IGxlbmd0aChtb2RlbCkgPT0gMCl7CiAgICByZXR1cm4oTkEpCiAgfQogIGVsc2V7CiAgICAjIEhlcmUgd2UgZm9jdXMgdW4gdGhlIGRlcml2YXRpdmUgYXJvdW5kIDAgdG8gZXN0aW1hdGUgdGhlIGJlaGF2aW9yIG9mIHRoZSBmZWF0dXJlCiAgICBtb2RlbCA8LSBtb2RlbFtbMV1dCiAgICBxdWFkcmF0aWMgPC0gKGxlbmd0aChtb2RlbCkgPT0gMykKCiAgICAjIERlcml2YXRpdmUgb2YgdGhlIG1vZGVsIGF0IFRUTAogICAgIyBmb3IgcXVhZHJhdGljIG1vZGVsCiAgICBpZiAocXVhZHJhdGljKXsKICAgICAgZGVyaXYgPC0gMiptb2RlbFtbJ0RPUzInXV0qVFRMICsgbW9kZWxbWydET1MnXV0KICAgIH0gCiAgICAjIGZvciBsaW5lYXIgbW9kZWwKICAgIGVsc2V7CiAgICAgIGRlcml2IDwtIG1vZGVsW1snRE9TJ11dCiAgICB9CiAgICAKICAgICMgUmV0dXJuaW5nIGVmZmVjdCBjb2VmZmljaWVudAogICAgaWYgKGFicyhkZXJpdikgPiBzbG9wZS50aHJlc2hvbGQpewogICAgICByZXR1cm4oZGVyaXYvYWJzKGRlcml2KSkKICAgIH0KICAgIGVsc2V7CiAgICAgIHJldHVybihOQSkKICAgIH0KICB9Cn0KYGBgCgoqKmNyZWF0ZS5kcnVnLmVmZmVjdC5kYXRhLmZyYW1lKioKCmBgYHtyfQojIEZ1bmN0aW9uIHdoaWNoIGNyZWF0ZXMgYSBkYXRhZnJhbWUgd2l0aCAKIyAxIHdoZW4gdGhlIGRydWcgaXMgYWZmZWN0aW5nIHRoZSBmZWF0dXJlIHRoZSBvcHBvc2l0ZSBkaXJlY3Rpb24gb2YgaXRzIG5vcm1hbCBiZWhhdmlvciBhdCBUVEwKIyAtMSB3aGVuIHRoZSBkcnVnIGlzIGFmZmVjdGluZyB0aGUgZmVhdHVyZSB0aGUgc2FtZSBkaXJlY3Rpb24gb2YgaXRzIG5vcm1hbCBiZWhhdmlvciBhdCBUVEwKIyAwIHdoZW4gdGhlIGVmZmVjdCBvZiB0aGUgZHJ1ZyBpcyBudWxsCiMgTkEgd2hlbiBiZWhhdmlvciBvZiB0aGUgZmVhdHVyZSBpcyBudWxsIG9yIGhhcmQgdG8gZXN0aW1hdGUgKGhpZ2ggcC12YWx1ZSkgb3IgaWYgd2UgbWlzcyBkYXRhIGluIHRoZSBkcnVnIGFzc2F5IHN0dWR5CgpjcmVhdGUuZHJ1Zy5lZmZlY3QuZGF0YS5mcmFtZSA8LSBmdW5jdGlvbihkcnVnLm5hbWUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5vcm1hbC5iZWhhdmlvci5wdmFsLnRocmVzaG9sZCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5vcm1hbC5iZWhhdmlvci5zbG9wZS50aHJlc2hvbGQsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkcnVnLnB2YWwudGhyZXNob2xkLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZHJ1Zy5zbG9wZS50aHJlc2hvbGQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRUTCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmVhdHVyZXMub2YuaW50ZXJlc3QpewogIAogICMgRGF0YWZyYW1lIGZlYXR1cmUgfiBzdGltdWxhdGlvbiBjb250YWluaW5nIHRoZSBmaW5hbCBlZmZlY3Qgb24gYSBkcnVnIG9uIGVhY2ggZmVhdHVyZSB1bmRlciBlYWNoIHN0aW11bGF0aW9uCiAgZHJ1Zy5lZmZlY3QuZGF0YWZyYW1lIDwtIG1vZGVsLnNjb3JlcyAlPiUKICAgICAgICAgICAgICAgICAgICAgICAgZmlsdGVyKGRydWcgPT0gZHJ1Zy5uYW1lKSAlPiUKICAgICAgICAgICAgICAgICAgICAgICAgcm93d2lzZSgpICU+JQogICAgICAgICAgICAgICAgICAgICAgICBtdXRhdGUoZHJ1Zy5iZWhhdmlvciA9IGRydWcuZWZmZWN0KHNsb3BlLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcHZhbCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNsb3BlLnRocmVzaG9sZCA9IGRydWcuc2xvcGUudGhyZXNob2xkLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcHZhbC50aHJlc2hvbGQgPSBkcnVnLnB2YWwudGhyZXNob2xkKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBvcHVsYXRpb24gPSBzdHJfZXh0cmFjdChmZWF0dXJlLCAiXlteX10rIiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZWFnZW50X3N0aW0gPSBzdHJfZXh0cmFjdChmZWF0dXJlLCAiKD88PV8pLiokIikpICU+JQogICAgICAgICAgICAgICAgICAgICAgICBzZWxlY3QocG9wdWxhdGlvbiwgZHJ1Zy5iZWhhdmlvciwgcmVhZ2VudF9zdGltKSAlPiUKICAgICAgICAgICAgICAgICAgICAgICAgcGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9IHJlYWdlbnRfc3RpbSwgdmFsdWVzX2Zyb20gPSBkcnVnLmJlaGF2aW9yKQogIAogICMgQ29uY2F0ZW5hdGlvbiBvZiBhbGwgaW5mb3JtYXRpb24gb24gdGhlIGZlYXR1cmUgbW9kZWxzICsgbm9ybWFsLmJlaGF2aW9yID0gKzEsIC0xIG9yIE5BCiAgbW9kZWwuaW5mbyA8LSBtZXJnZShkZl9tb2RlbHMsIGN1cnZlLmNsYXNzaWZpY2F0aW9uLCBieS54ID0gImZlYXR1cmUiLCBieS55ID0gImN5dG9mIikgJT4lCiAgICAgICAgICAgICAgICByb3d3aXNlKCkgJT4lCiAgICAgICAgICAgICAgICBtdXRhdGUobm9ybWFsLmJlaGF2aW9yID0gZmVhdHVyZS5ub3JtYWwuYmVoYXZpb3IuYXQuVFRMKG1vZGVsLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwdmFsLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbm9ybWFsLmJlaGF2aW9yLnNsb3BlLnRocmVzaG9sZCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbm9ybWFsLmJlaGF2aW9yLnB2YWwudGhyZXNob2xkLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBUVEwpLAogICAgICAgICAgICAgICAgICAgICAgICMgQWRkaW5nIHNvbWUgbnVhbmNlIHRvIHRoZSBpbXBvcnRhbmNlIG9mIHRoZSBiZWhhdmlvcgogICAgICAgICAgICAgICAgICAgICAgIG5vcm1hbC5iZWhhdmlvciA9IGlmZWxzZShmZWF0dXJlICVpbiUgZmVhdHVyZXMub2YuaW50ZXJlc3QsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5vcm1hbC5iZWhhdmlvciwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbm9ybWFsLmJlaGF2aW9yLzIpKQoKICAjIERhdGFmcmFtZSBmZWF0dXJlIH4gc3RpbXVsYXRpb24gY29udGFpbmluZyB0aGUgdmFsdWVzIG9mIG5vcm1hbC5iZWhhdmlvcgogIGJlaGF2aW9yLmRhdGFmcmFtZSA8LSBtb2RlbC5pbmZvICU+JQogICAgICAgICAgICAgICAgICAgICAgICAgIG11dGF0ZShwb3B1bGF0aW9uID0gc3RyX2V4dHJhY3QoZmVhdHVyZSwgIl5bXl9dKyIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZWFnZW50X3N0aW0gPSBzdHJfZXh0cmFjdChmZWF0dXJlLCAiKD88PV8pLiokIikpICU+JQogICAgICAgICAgICAgICAgICAgICAgICAgIHNlbGVjdChwb3B1bGF0aW9uLCBub3JtYWwuYmVoYXZpb3IsIHJlYWdlbnRfc3RpbSkgJT4lCiAgICAgICAgICAgICAgICAgICAgICAgICAgcGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9IHJlYWdlbnRfc3RpbSwgdmFsdWVzX2Zyb20gPSBub3JtYWwuYmVoYXZpb3IpICU+JQogICAgICAgICAgICAgICAgICAgICAgICAgICMgcmVtb3ZpbmcgZmVhdHVyZXMgbm90IG1lYXN1cmVkIGluIGJvdGggc3R1ZGllcyAoZHJ1Z3MgYW5kIE9PTCkKICAgICAgICAgICAgICAgICAgICAgICAgICAjIGBTVEFUM19MUFNgLCBgU1RBVDVfTFBTYCwgYFNUQVQxX0xQU2AsIGBTVEFUNl9MUFNgLCBgU1RBVDFfR01DU0ZgCiAgICAgICAgICAgICAgICAgICAgICAgICAgIyAiU1RBVDFfdW5zdGltIgogICAgICAgICAgICAgICAgICAgICAgICAgIGZpbHRlcihwb3B1bGF0aW9uICVpbiUgZHJ1Zy5lZmZlY3QuZGF0YWZyYW1lJHBvcHVsYXRpb24pICU+JQogICAgICAgICAgICAgICAgICAgICAgICAgIHNlbGVjdChvbmVfb2YoY29sbmFtZXMoZHJ1Zy5lZmZlY3QuZGF0YWZyYW1lKSkpCiAgICAgICAgICAgICAgICAgICAgICAgIAogICMgRGF0YWZyYW1lIGZlYXR1cmUgfiBzdGltdWxhdGlvbiBjb250YWluaW5nIHRoZSBwcm9kdWN0IG9mIGJlaGF2aW9yLm1hdHJpeCBhbmQgZHJ1Zy5lZmZlY3QubWF0cml4CiAgZHJ1Zy5maW5hbC5lZmZlY3QuZGF0YWZyYW1lPC0gbWVyZ2UocGl2b3RfbG9uZ2VyKHNlbGVjdChiZWhhdmlvci5kYXRhZnJhbWUsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG9uZV9vZihjb2xuYW1lcyhkcnVnLmVmZmVjdC5kYXRhZnJhbWUpKSksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xzID0gLXBvcHVsYXRpb24sIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuYW1lc190byA9ICJyZWFnZW50X3N0aW0iLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdmFsdWVzX3RvID0gIm5vcm1hbC5iZWhhdmlvciIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBpdm90X2xvbmdlcihzZWxlY3QoZHJ1Zy5lZmZlY3QuZGF0YWZyYW1lLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgb25lX29mKGNvbG5hbWVzKGJlaGF2aW9yLmRhdGFmcmFtZSkpKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbHMgPSAtcG9wdWxhdGlvbiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5hbWVzX3RvID0gInJlYWdlbnRfc3RpbSIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2YWx1ZXNfdG8gPSAiZHJ1Zy5iZWhhdmlvciIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJ5ID0gYygicG9wdWxhdGlvbiIsICJyZWFnZW50X3N0aW0iKSkgJT4lCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcm93d2lzZSgpICU+JQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG11dGF0ZShkcnVnLmZpbmFsLmVmZmVjdCA9IGlmZWxzZShpcy5uYShub3JtYWwuYmVoYXZpb3IpIHx8CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaXMubmEoZHJ1Zy5iZWhhdmlvciksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIE5BLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAtbm9ybWFsLmJlaGF2aW9yKmRydWcuYmVoYXZpb3IpKSAlPiUKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZWxlY3QocG9wdWxhdGlvbiwgcmVhZ2VudF9zdGltLCBkcnVnLmZpbmFsLmVmZmVjdCkgJT4lCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9IHJlYWdlbnRfc3RpbSwgdmFsdWVzX2Zyb20gPSBkcnVnLmZpbmFsLmVmZmVjdCkKCiAgcmV0dXJuKGRydWcuZmluYWwuZWZmZWN0LmRhdGFmcmFtZSkKfQpgYGAKCiMjIyBGZWF0dXJlcyBvZiBpbnRlcmVzdAoKRm9yIG5vdywgd2UgZG9uJ3QgaGF2ZSBhIE1MIG1vZGVsIHdpdGggc2VsZWN0ZWQgZmVhdHVyZXMgaGVscGluZyB1cyBkaXNjcmltaW5hdGUgd2hpY2ggZmVhdHVyZXMgYXJlIG1vcmUgaW1wb3J0YW50IHRvIGxvb2sgYXQgc28gd2UgYXJlIGxvb2tpbmcgYXQgdHdvIHNldHMgb2YgZmVhdHVyZXMgOgotIHRoZSB0b3AgMTUgQ3l0b2YgZmVhdHVyZXMgZnJvbSB0aGUgT09MIHBhcGVyCi0gdGhlIGZlYXR1cmVzIGZyb20gdGhlIHVuaXZhcmlhdGUgYW5hbHlzaXMgd2l0aCBhbiBhYnNvbHV0ZSBTcGVhcm1hbiBzY29yZSA+IDAuMwoKKipUb3AgMTUgZmVhdHVyZXMgZnJvbSBPT0wgcGFwZXIqKgoKYGBge3J9CiMgVG9wIGltbXVub21lIGZlYXR1cmVzIGZyb20gdGhlIE9PTCBzdHVkeQojIHdlIGFzc29jaWF0ZSBhIGNvZWZmICsxIChpbmNyZWFzaW5nKSBvciAtMSAoZGVjcmVhc2luZykgdG8gdGhlIGZlYXR1cmVzCk9PTC50b3AuaW1tdW5vbWUuZmVhdHVyZXMgPC0gbGlzdCgiQ0Q1NmxvQ0QxNnBvc05LX1NUQVQxX0lGTmEiPTEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIEdyYW51bG9jeXRlcyBtaXNzaW5nIGluIHRoZSBkcnVnIGFzc2F5IHN0dWR5CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiQ0Q1NmhpQ0QxNm5lZ05LX1NUQVQxX0lGTmEiPTEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiQ0Q0VG5haXZlX01BUEtBUEsyX0lGTmEiPTEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAibmNNQ3NfQ1JFQl9HTUNTRiI9LTEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiQ0Q4VGNtX01BUEtBUEsyX3Vuc3RpbSI9MSwgIy0xIGF0IFRUTCA9IDAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJDRDhUZW1fTUFQS0FQSzJfdW5zdGltIj0xLCAjLTEgYXQgVFRMID0gMAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInBEQ3NfU1RBVDFfSUZOYSI9MSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJCY2VsbHNfTUFQS0FQSzJfTFBTIj0xLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkNENFRlbV9NQVBLQVBLMl91bnN0aW0iPTEsICMtMSBhdCBUVEwgPSAwCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiQ0Q4VGNtX01BUEtBUEsyX0lGTmEiPTEsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkNEOFRlbV9NQVBLQVBLMl9JRk5hIj0xLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBCY2VsbHMgbWlzc2luZyBpbiB0aGUgZHJ1ZyBhc3NheSBzdHVkeQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkNENFRlbV9ORmtCX0lMMjQ2Ij0tMSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJDRDRUY21fSWtCX3Vuc3RpbSI9MSwgIy0xIGF0IFRUTCA9IDAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJtRENzX1NUQVQ2X0lGTmEiPTEsICMtMSBhdCBUVEwgPSAwCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicERDc19TVEFUNl9JRk5hIj0xLCAjLTEgYXQgVFRMID0gMAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIm1EQ3NfTUFQS0FQSzJfdW5zdGltIj0tMSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicERDc19NQVBLQVBLMl91bnN0aW0iPS0xCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApCmBgYAoKKipUb3AgZmVhdHVyZXMgZnJvbSB0aGUgdW5pdmFyaWF0ZSBhbmFseXNpcyoqCgpgYGB7cn0KIyBUb3AgaW1tdW5vbWUgZmVhdHVyZXMgZnJvbSB0aGUgdW5pdmFyaWF0ZSBhbmFseXNpcyBvbiBPT0wgZGF0YQojIHdlIGFzc29jaWF0ZSBhIGNvZWZmICsxIChpbmNyZWFzaW5nKSBvciAtMSAoZGVjcmVhc2luZykgdG8gdGhlIGZlYXR1cmVzCgp1bml2YXJpYXRlLk9PTC5mZWF0dXJlcyA8LSBhcHBseShzcGVhcm1hbl9jb3JbYWJzKHNwZWFybWFuX2NvciRgU3BlYXJtYW4gY29ycmApID4gMC4zLF0sICMgdGFraW5nIGZlYXR1cmVzIHdpdGggfFNwZWFybWFucnwgPiAwLjMKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgMSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZnVuY3Rpb24ocm93KXsgIyBhc3NvY2lhdGluZyB0aGUgZmVhdHVyZSBuYW1lIHRvICsxIChpbmNyZWFzaW5nKSBvciAtMSAoZGVjcmVhc2luZykKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBrZXkgPC0gcm93W1sxXV0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAoIWlzLm5hKGtleSkpIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZhbHVlIDwtIGFzLm51bWVyaWMocm93W1syXV0pL2Ficyhhcy5udW1lcmljKHJvd1tbMl1dKSkKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNldE5hbWVzKGxpc3QodmFsdWUpLCBrZXkpCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfSAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfSkgJT4lCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRmlsdGVyKGZ1bmN0aW9uKHgpICFpcy5udWxsKHgpLCAuKSAlPiUKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB1bmxpc3QocmVjdXJzaXZlPUZBTFNFKQpgYGAKCioqVG9wIGZlYXR1cmVzIGZyb20gZmVhdHVyZS5pbmRleCoqCgpgYGB7cn0KIyBUb3AgaW1tdW5vbWUgZmVhdHVyZXMgZnJvbSB0aGUgZmVhdHVyZS5pbmRleAojIHdlIGFzc29jaWF0ZSBhIGNvZWZmICsxIChpbmNyZWFzaW5nKSBvciAtMSAoZGVjcmVhc2luZykgdG8gdGhlIGZlYXR1cmVzCgojIFRpbWVwb2ludCBvZiBpbnRlcmVzdApUVEwgPC0gLTg0CgojIFRocmVzaG9sZHMgdG8gY2FsY3VsYXRlIHRoZSBub3JtYWwgYmVoYXZpb3Igb2YgYSBnaXZlbiBmZWF0dXJlCm5vcm1hbC5iZWhhdmlvci5zbG9wZS50aHJlc2hvbGQgPC0gMC4Kbm9ybWFsLmJlaGF2aW9yLnB2YWwudGhyZXNob2xkIDwtIDEwCgojIEluZm8gKG1vZGVsLCBwdmFsLCBybXNlLCAuLi4pIG9mIHRoZSBtb2RlbHMgYXQgdGhlIHRpbWVwb2ludCBUVEwKbW9kZWwuaW5mbyA8LSBtZXJnZShkZl9tb2RlbHMsIGN1cnZlLmNsYXNzaWZpY2F0aW9uLCBieS54ID0gImZlYXR1cmUiLCBieS55ID0gImN5dG9mIikgJT4lCiAgICAgICAgICAgICAgcm93d2lzZSgpICU+JQogICAgICAgICAgICAgIG11dGF0ZShub3JtYWwuYmVoYXZpb3IgPSBmZWF0dXJlLm5vcm1hbC5iZWhhdmlvci5hdC5UVEwobW9kZWwsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwdmFsLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5vcm1hbC5iZWhhdmlvci5zbG9wZS50aHJlc2hvbGQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBub3JtYWwuYmVoYXZpb3IucHZhbC50aHJlc2hvbGQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRUTCkpCiMgTGlzdCBvZiB0aGUgZmVhdHVyZXMgYW5kIHRoZWlyIGJlaGF2aW9yCnRvcC5mZWF0dXJlLmluZGV4IDwtIGZlYXR1cmUuaW5kZXggJT4lCiAgICAgICAgICAgICAgICAgICAgICAgIGZpbHRlcihtb2RlbF9pbmRleCA+IDApICU+JQogICAgICAgICAgICAgICAgICAgICAgICBsZWZ0X2pvaW4obW9kZWwuaW5mbywgYnk9ImZlYXR1cmUiKSAlPiUKICAgICAgICAgICAgICAgICAgICAgICAgc2VsZWN0KGZlYXR1cmUsIG5vcm1hbC5iZWhhdmlvcikgJT4lCiAgICAgICAgICAgICAgICAgICAgICAgIHB1bGwobm9ybWFsLmJlaGF2aW9yKSAlPiUgCiAgICAgICAgICAgICAgICAgICAgICAgIHNldE5hbWVzKHB1bGwoZmVhdHVyZS5pbmRleFsoZmVhdHVyZS5pbmRleCRtb2RlbF9pbmRleCA+IDApICYgIShpcy5uYShmZWF0dXJlLmluZGV4JG1vZGVsX2luZGV4KSksXSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmVhdHVyZSkpICU+JQogICAgICAgICAgICAgICAgICAgICAgICBhcy5saXN0KCkKYGBgCgojIyMgRHJ1Z3MgcmFua2luZwoKSGVyZSB3ZSByYW5rIHRoZSBkcnVncyBiYXNlZCBvbiB0aGVpciBlZmZlY3Qgb24gdGhlIGNob3NlbiBmZWF0dXJlcyBvZiBpbnRlcmVzdC4gV2UgYXNzb2NpYXRlIGEgKzEgc2NvcmUgd2hlbiB0aGUgZHJ1ZyBoYXMgYW4gZWZmZWN0IHdoaWNoIGlzIG9wcG9zaXRlIHRvIHRoZSAibm9ybWFsIiBiZWhhdmlvci8gdHJlbmQgb2YgdGhlIGZlYXR1cmUgYW5kIC0xIHdoZW4gdGhlIGVmZmVjdCBvZiB0aGUgZHJ1ZyBpcyBjb2xpbmVhciB0byB0aGUgIm5vcm1hbCIgZmVhdHVyZSBiZWhhdmlvci4KCmBgYHtyfQojIE1vZGVscyBvZiBpbnRlcmVzdApmaW5hbC5tb2RlbCA8LSBwc2V1ZG9fbG9nMTAubWVkaWFuLmxpbmVhci5tb2RlbApmaW5hbC5tb2RlbC50eXBlIDwtICJtZWRpYW4iICMiaW5kaXZpZHVhbCIgb3IgIm1peGVkIiBvciAibWVkaWFuIgoKIyBDaG9zaW5nIGZlYXR1cmVzIG9mIGludGVyZXN0CmZlYXR1cmVfY2hvaWNlIDwtICJ0b3BfZmVhdHVyZV9pbmRleF9mZWF0dXJlcyIKT09MX2ZlYXR1cmVzIDwtIHRvcC5mZWF0dXJlLmluZGV4CgojIENob3NpbmcgdGhyZXNob2xkcyBvdmVyIG9yIHVuZGVyIHdoaWNoIHdlIGNvbnNpZGVyIHRoZSBlZmZlY3Qgb2YgdGhlIGRydWcgYXMgcmVsZXZhbnQKc2xvcGUudGhyZXNob2xkIDwtIDAKcHZhbC50aHJlc2hvbGQgPC0gMQpgYGAKCkNhbGN1bGF0aW9uIG9mIHRoZSBzY29yZXMgYW5kIHJhbmtpbmcgb2YgdGhlIGZlYXR1cmVzLgoKKipkcnVnLnJhbmtpbmcgOioqIGRhdGFmcmFtZSBjb250YWluaW5nIHRoZSBuYW1lIG9mIHRoZSBkcnVncyBhbmQgdGhlaXIgc2NvcmUuCgpgYGB7cn0KZHJ1Zy5yYW5raW5nIDwtIGRhdGEuZnJhbWUoZHJ1ZyA9IGNoYXJhY3RlcigpLAogICAgICAgICAgICAgICAgICAgICAgICAgICBzY29yZSA9IG51bWVyaWMoKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgc3RyaW5nc0FzRmFjdG9ycyA9IEZBTFNFKQoKIyBHZXR0aW5nIGEgbm9ybWl6ZWQgbG9nIHRyYW5zZm9ybSBvZiB0aGUgZmVhdHVyZSBpbmRleCB0byBiZSB1c2VkIGFzIGNvZWZmaWNpZW50IGluIHRoZSBzY29yZQpub3JtLmxvZy5mZWF0dXJlLmluZGV4IDwtIGZlYXR1cmUuaW5kZXggJT4lCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBtdXRhdGUobG9nLm1vZGVsX2luZGV4ID0gbG9nMTAoMSArIG1vZGVsX2luZGV4KSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBub3JtLmxvZy5tb2RlbF9pbmRleCA9IGxvZy5tb2RlbF9pbmRleC9zdW0obG9nLm1vZGVsX2luZGV4LCBuYS5ybT1UUlVFKSkgJT4lCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZWxlY3QoZmVhdHVyZSwgbm9ybS5sb2cubW9kZWxfaW5kZXgpICU+JQogICAgICAgICAgICAgICAgICAgICAgICBwdWxsKG5vcm0ubG9nLm1vZGVsX2luZGV4KSAlPiUgCiAgICAgICAgICAgICAgICAgICAgICAgIHNldE5hbWVzKHB1bGwoZmVhdHVyZS5pbmRleCwgZmVhdHVyZSkpICU+JQogICAgICAgICAgICAgICAgICAgICAgICBhcy5saXN0KCkKCiMgQ2FsY3VsYXRpbmcgdGhlIHNjb3JlCmZvciAoZHJ1ZyBpbiB1bmlxdWUoZmluYWwubW9kZWwkZHJ1ZykpewogIHNjb3JlIDwtIDAKICAjIFdlIHN1bSB0aGUgc2NvcmVzIG92ZXIgYWxsIHRoZSBmZWF0dXJlcyBmb3IgZWFjaCBkcnVnCiAgZm9yIChmZWF0dXJlIGluIG5hbWVzKE9PTF9mZWF0dXJlcykpewogICAgIyBHZXR0aW5nIHRoZSBkcnVnIGVmZmVjdCBvbiB0aGUgZmVhdHVyZQogICAgc2xvcGUgPC0gbW9kZWwuc2NvcmVzWyhtb2RlbC5zY29yZXMkZmVhdHVyZSA9PSBmZWF0dXJlKSAmIChtb2RlbC5zY29yZXMkZHJ1ZyA9PSBkcnVnKSxdJHNsb3BlCiAgICBwdmFsIDwtIG1vZGVsLnNjb3Jlc1sobW9kZWwuc2NvcmVzJGZlYXR1cmUgPT0gZmVhdHVyZSkgJiAobW9kZWwuc2NvcmVzJGRydWcgPT0gZHJ1ZyksXSRwdmFsCiAgICAjIFNvbWV0aW1lcyB0aGUgdmFsdWVzIG9mIHNsb3BlIGFuZC9vciBwdmFsIGlzIGVtcHR5IHNvIHdlIGZpbGwgd2l0aCAwIHRoZXNlIHZhbHVlcwogICAgZHJ1Z19lZmZlY3QgPC0gaWZlbHNlKChsZW5ndGgoc2xvcGUpKmxlbmd0aChwdmFsKSA9PSAwKSB8fCAoaXMubmEoc2xvcGUpIHwgaXMubmEocHZhbCkpLAogICAgICAgICAgICAgICAgICAgICAgICAgIDAsCiAgICAgICAgICAgICAgICAgICAgICAgICAgZHJ1Zy5lZmZlY3Qoc2xvcGUsIHB2YWwsIHNsb3BlLnRocmVzaG9sZCwgcHZhbC50aHJlc2hvbGQpKQogICAgIyBBZGRpbmcgdGhlIGluZGl2aWR1YWwgc2NvcmVzIG9mIHRoZSBkcnVnIGVhY2ggZmVhdHVyZSAKICAgIHNjb3JlIDwtIHNjb3JlIC0gZHJ1Z19lZmZlY3QqT09MX2ZlYXR1cmVzW1tmZWF0dXJlXV0qbm9ybS5sb2cuZmVhdHVyZS5pbmRleFtbZmVhdHVyZV1dCiAgfQogICMgQWRkaW5nIHRoZSBkcnVnIGFuZCBpdHMgc2NvcmUgdG8gZHJ1Zy5yYW5raW5nCiAgZHJ1Zy5yYW5raW5nIDwtIHJiaW5kKGRydWcucmFua2luZywKICAgICAgICAgICAgICAgICAgICAgICAgZGF0YS5mcmFtZShkcnVnPWRydWcsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2NvcmU9c2NvcmUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3RyaW5nc0FzRmFjdG9ycyA9IEZBTFNFKSkKfQojIEFycmFuZ2luZyB0aGUgZHJ1Z3MgdG8gc2VlIHRoZSBiZXN0IGRydWdzIG9uIHRvcApkcnVnLnJhbmtpbmcgPC0gZHJ1Zy5yYW5raW5nICU+JSBhcnJhbmdlKGRlc2Moc2NvcmUpKQpkcnVnLnJhbmtpbmcKYGBgCgojIyBWaXN1YWxpemF0aW9uCgojIyMgTW9kZWxzIHZlcnN1cyAibm9ybWFsIiBiZWhhdmlvcgoKQXV4aWxpYXJ5IGZ1bmN0aW9uIHRvIHBsb3QgdGhlIG1peGVkIG1vZGVsLgoKYGBge3J9CiMgRnVuY3Rpb24gdGFraW5nIHRoZSBuYW1lIG9mIGEgZmVhdHVyZSwgbmFtZSBvZiBhIGRydWcgYW5kIGEgcHZhbHVlCiMgUmV0dXJuaW5nIGEgcGxvdCBvZiB0aGUgbW9kZWwgY29ycmVzcG9uZGluZyB0byB0aGUgZmVhdHVyZSBhbmQgZHJ1ZwoKcGxvdF9kcnVnX2ZlYXR1cmVfbW9kZWwgPC0gZnVuY3Rpb24odGFyZ2V0X2RydWcsIHRhcmdldF9mZWF0dXJlLCBwX3ZhbHVlKXsKICAjIEdldHRpbmcgdGhlIG1vZGVsIGFzc29jaWF0ZWQgdG8gdGhlIHRhcmdldF9kcnVnIGFuZCB0aGUgdGFyZ2V0X2ZlYXR1cmUKICB0YXJnZXRfbW9kZWwgPC0gZmluYWwubW9kZWwkbW9kZWxbZmluYWwubW9kZWwkZmVhdHVyZSA9PSB0YXJnZXRfZmVhdHVyZSAmIGZpbmFsLm1vZGVsJGRydWcgPT0gdGFyZ2V0X2RydWddW1sxXV0KICAjIEdldHRpbmcgdGhlIHB2YWwgYXNzb2NpYXRlZCB3aXRoIHRoZSB0YXJnZXRfbW9kZWwKICBwdmFsIDwtIGZpbmFsLm1vZGVsJHB2YWxbZmluYWwubW9kZWwkZmVhdHVyZSA9PSB0YXJnZXRfZmVhdHVyZSAmIGZpbmFsLm1vZGVsJGRydWcgPT0gdGFyZ2V0X2RydWddW1sxXV0KICAjIFNldHRpbmcgdGhlIGRvc2UgdmFsdWVzIHRvIHRoZWlyIHBzZXVkbyBsb2cgdHJhbnNmb3JtCiAgRG9zZXJlc3BvbnNlIDwtIEFsbFBlbkRvc2VyZXNwb25zZSAlPiUKICAgICAgICAgICAgICAgICAgICBtdXRhdGUoZG9zZSA9IHBzZXVkb19sb2dfZG9zZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgSUQgPSBhcy5mYWN0b3IoSUQpKSAlPiUKICAgICAgICAgICAgICAgICAgICBmaWx0ZXIoaXMuZmluaXRlKGRvc2UpKQogICMgU3Vic2V0IG9mIHRoZSBkYXRhIGZvciB0aGUgY2hvc2VuIGZlYXR1cmUgYW5kIGRydWcKICBkYXRhIDwtIERvc2VyZXNwb25zZSAlPiUgCiAgICAgICAgICAgICAgZmlsdGVyKGZlYXR1cmUgPT0gISF0YXJnZXRfZmVhdHVyZSwKICAgICAgICAgICAgICAgICAgICAgZHJ1ZyA9PSAhIXRhcmdldF9kcnVnKSAlPiUKICAgICAgICAgICAgICBzZWxlY3QoSUQsIGRvc2UsIHZhbHVlKQogICAgCiAgIyMjIFBMT1QgVEhFIE1FRElBTiBNT0RFTAogIGlmIChmaW5hbC5tb2RlbC50eXBlID09ICJtZWRpYW4iKXsKICAgICMgQ29lZmZpY2llbnRzIG9mIHRoZSBzZWxlY3RlZCBtb2RlbAogICAgbW9kZWxfY29lZnMgPC0gY29lZih0YXJnZXRfbW9kZWwpICU+JQogICAgICAgICAgICAgICAgICAgICAgYXMuZGF0YS5mcmFtZSgpICU+JQogICAgICAgICAgICAgICAgICAgICAgdCgpICU+JQogICAgICAgICAgICAgICAgICAgICAgYGNvbG5hbWVzPC1gKGMoIkludGVyY2VwdCIsICJTbG9wZSIpKQogICAgCiAgICBkYXRhX3JhbmkgPC0gbWVyZ2UoZGF0YSwgbW9kZWxfY29lZnMpCiAgICAKICAgICMgUGxvdAogICAgcGxvdCA8LSBnZ3Bsb3QoZGF0YV9yYW5pLCBhZXMoeD1kb3NlLCB5PXZhbHVlLCBncm91cD1kb3NlKSkgKwogICAgICAgICAgICAgIGdlb21fYm94cGxvdCgpICsKICAgICAgICAgICAgICBnZW9tX2FibGluZShhZXMoaW50ZXJjZXB0ID0gSW50ZXJjZXB0LCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2xvcGUgPSBTbG9wZSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgc2l6ZSA9IDEuKSArCiAgICAgICAgICAgICAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gInRvcCIpCiAgfQogIAogICMjIyBQTE9UIFRIRSBJTkRJVklEVUFMIE1PREVMCiAgaWYgKGZpbmFsLm1vZGVsLnR5cGUgPT0gImluZGl2aWR1YWwiKXsKICAgICMgQ29lZmZpY2llbnRzIG9mIHRoZSBzZWxlY3RlZCBtb2RlbAogICAgbW9kZWxfY29lZnMgPC0gdGFyZ2V0X21vZGVscyAlPiUKICAgICAgICAgICAgICAgICAgICAgIG11dGF0ZShTbG9wZSA9IHNhcHBseShtb2RlbCwgZnVuY3Rpb24oeCkgY29lZih4KVsiZG9zZSJdKSwKICAgICAgICAgICAgICAgICAgICAgIEludGVyY2VwdCA9IHNhcHBseShtb2RlbCwgZnVuY3Rpb24oeCkgY29lZih4KVsiKEludGVyY2VwdCkiXSksCiAgICAgICAgICAgICAgICAgICAgICBJRCA9IGFzLmZhY3RvcihJRCkpCiAgICAKICAgIGRhdGFfcmFuaSA8LSBsZWZ0X2pvaW4oZGF0YSwgbW9kZWxfY29lZnMsIGJ5ID0gIklEIikKICAgIAogICAgIyBQbG90CiAgICBwbG90IDwtIGdncGxvdChkYXRhID0gZGF0YV9yYW5pLCBtYXBwaW5nID0gYWVzKHggPSBkb3NlLCB5ID0gdmFsdWUsIGNvbG91ciA9IElEKSkgKwogICAgICAgICAgICAgIGdlb21fcG9pbnQobmEucm0gPSBULCBhbHBoYSA9IDAuNSkgKwogICAgICAgICAgICAgIGdlb21fYWJsaW5lKGFlcyhpbnRlcmNlcHQgPSBJbnRlcmNlcHQsIHNsb3BlID0gU2xvcGUsIGNvbG91ciA9IElEKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgc2l6ZSA9IDEuKSArCiAgICAgICAgICAgICAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gInRvcCIpCiAgfQogIAogICMjIyBQTE9UIFRIRSBNSVhFRCBMSU5FQVIgTU9ERUwKICBpZiAoZmluYWwubW9kZWwudHlwZSA9PSAibWl4ZWQiKXsKICAgICMgQ29lZmZpY2llbnRzIG9mIHRoZSBzZWxlY3RlZCBtb2RlbAogICAgbW9kZWxfY29lZnMgPC0gY29lZih0YXJnZXRfbW9kZWwpJElEICU+JSAKICAgICAgICAgICAgICAgICAgICAgIHJlbmFtZShJbnRlcmNlcHQgPSBgKEludGVyY2VwdClgLCBTbG9wZSA9IGRvc2UpICU+JSAKICAgICAgICAgICAgICAgICAgICAgIHJvd25hbWVzX3RvX2NvbHVtbigiSUQiKQogICAgCiAgICBkYXRhX3JhbmkgPC0gbGVmdF9qb2luKGRhdGEsIG1vZGVsX2NvZWZzLCBieSA9ICJJRCIpCiAgICAKICAgICMgUGxvdAogICAgcGxvdCA8LSBzdXBwcmVzc1dhcm5pbmdzKGdncGxvdChkYXRhID0gZGF0YV9yYW5pLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4ID0gZG9zZSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeSA9IHZhbHVlLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvdXIgPSBJRCkpICsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdlb21fcG9pbnQobmEucm0gPSBULCBhbHBoYSA9IDAuNSkgKwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2VvbV9hYmxpbmUoYWVzKGludGVyY2VwdCA9IEludGVyY2VwdCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2xvcGUgPSBTbG9wZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvdXIgPSBJRCksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzaXplID0gMS4pKQogIH0KICAKICAjIFJlbW92aW5nIHVuZWNlc3NhcnkgbGFiZWxzIGFuZCBhZGRpbmcgdGl0bGUKICBwbG90IDwtIHBsb3QgKyAKICAgICAgZ2d0aXRsZShwYXN0ZSh0YXJnZXRfZmVhdHVyZSwgcHZhbCwgc2VwPSIsXG5wID0gIikpICsKICAgICAgeGxhYihOVUxMKSArICAjIFJlbW92ZSB4LWF4aXMgbGFiZWwKICAgICAgeWxhYihOVUxMKSArICAjIFJlbW92ZSB5LWF4aXMgbGFiZWwKICAgICAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKSArCiAgICAgIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDYpKQogIAogIHJldHVybihwbG90KQp9CmBgYAoKUGxvdHRpbmcgdGhlIGluZGl2aWR1YWwgbW9kZWxzIG9mIHRoZSBkcnVnIG9uIHRoZSBjaG9zZW4gZmVhdHVyZXMgdmVyc3VzIHRoZSBub3JtYWwgYmVoYXZpb3Igb2YgdGhlIE9PTCBmZWF0dXJlIGluIG9yZGVyIHRvIHNlZSBpZiB0aGUgdHJlbmRzIGFyZSBhY3R1YWxseSBvcHBvc2l0ZXMgKG9yIGNvbGluZWFyKSBhbmQgdGhhdCB0aGUgbW9kZWxzIGZpdCB0aGUgZGF0YS4KCmBgYHtyfQojIFNlbGVjdGluZyBhIHNwZWNpZmljIGRydWcgYW5kIHBsb3R0aW5nIHRoZSBjb21wYXJpc29uIG9mIHRoZSBtb2RlbCBvZiB0aGUgZmVhdHVyZXMgd2l0aCB0aGUgbWl4ZWQgbW9kZWwgb2YgdGhlIGRydWcKdGFyZ2V0X2RydWcgPC0gIk1ldGZvcm1pbiIKIyBUaW1lIHRvIGxhYm9yIG9mIGludGVyZXN0ICh3aWxsIHBsb3QgdGhlIGRlcml2YXRpdmUgYXQgdGhpcyBwb2ludCkKVFRMIDwtIC04NAoKcGxvdHMgPC0gbGlzdCgpCmkgPC0gMApmb3IgKHRhcmdldF9mZWF0dXJlIGluIG5hbWVzKE9PTF9mZWF0dXJlcykpIHsKICB0YXJnZXRfbW9kZWwgPC0gZmluYWwubW9kZWwkbW9kZWxbZmluYWwubW9kZWwkZmVhdHVyZSA9PSB0YXJnZXRfZmVhdHVyZSAmIGZpbmFsLm1vZGVsJGRydWcgPT0gdGFyZ2V0X2RydWddCiAgcHZhbCA8LSBtb2RlbC5zY29yZXNbKG1vZGVsLnNjb3JlcyRmZWF0dXJlID09IHRhcmdldF9mZWF0dXJlKSAmIChtb2RlbC5zY29yZXMkZHJ1ZyA9PSB0YXJnZXRfZHJ1ZyksXSRwdmFsCiAgCiAgIyBXZSBvbmx5IHBsb3QgZmVhdHVyZXMgb24gd2hpY2ggdGhlIHNjb3JlIGhhcyBiZWVuIGNhbGN1bGF0ZWQgKHdpdGggbWl4ZWQgbW9kZWwgaGF2aW5nIGEgcHZhbHVlIDwgcHZhbCA8IHB2YWwudGhyZXNob2xkKQogIGlmICgobGVuZ3RoKHB2YWwpID4gMCkgJiYKICAgICAgKCFpcy5uYShwdmFsKSkgJiYKICAgICAgKHB2YWwgPCBwdmFsLnRocmVzaG9sZCkgJiYgCiAgICAgIChsZW5ndGgodGFyZ2V0X21vZGVsKT4wKSl7CiAgICAjIENvdW50aW5nIHRoZSBudW1iZXIgb2YgcGxvdHMKICAgIGkgPC0gaSArIDIKICAgIAogICAgIyMjIFBMT1QgVEhFIElORElWSURVQUwgTElORUFSIE1PREVMCiAgICBtb2RlbF9jb2VmX3Bsb3QgPC0gcGxvdF9kcnVnX2ZlYXR1cmVfbW9kZWwodGFyZ2V0X2RydWcsIHRhcmdldF9mZWF0dXJlLCBwdmFsKQogICAgIyBBZGRpbmcgcGxvdCB0byB0aGUgbGlzdCBvZiBwbG90cwogICAgcGxvdHNbW3RhcmdldF9mZWF0dXJlXV0gPC0gbW9kZWxfY29lZl9wbG90CgogICAgCiAgICAjIyMgUExPVCBUSEUgQVNTT0NJQVRFRCBPT0wgRkVBVFVSRQogICAgIyBHZXR0aW5nIHRoZSBjb2VmZmljaWVudHMgYW5kIGNsYXNzIG9mIHRoZSBtb2RlbAogICAgY29lZnMgPC0gZGZfbW9kZWxzW2RmX21vZGVscyRmZWF0dXJlID09IHRhcmdldF9mZWF0dXJlLF0kbW9kZWxbWzFdXVtbMV1dCiAgICAKICAgICMgQnVpbGRpbmcgdGhlIHByZWRpY3Rpb25zCiAgICB5IDwtIE9PTF9kYXRhWywgdGFyZ2V0X2ZlYXR1cmVdCiAgICBpbnRlcmNlcHQgPC0gY29lZnNbWycoSW50ZXJjZXB0KSddXQogICAgaWYgKGxlbmd0aChjb2VmcykgPT0gMyl7ICMgcXVhZHJhdGljIG1vZGVsCiAgCiAgICAgIGEgPC0gY29lZnNbWydET1MyJ11dCiAgICAgIGIgPC0gY29lZnNbWydET1MnXV0KICAgICAgeV9wcmVkIDwtIGludGVyY2VwdCArIGIgKiBET1MgKyBhICogRE9TXjIKICAgICAgeV9kZXJpdiA8LSAoMiphKlRUTCArIGIpKihET1MgLSBUVEwpICsgKGludGVyY2VwdCArIGIgKiBUVEwgKyBhICogVFRMXjIpCiAgICB9CiAgICBlbHNleyAjIGxlbmd0aChjb2VmcykgPT0gMiwgbGluZWFyIG1vZGVsCiAgICAgIHNsb3BlIDwtIGNvZWZzW1snRE9TJ11dCiAgICAgIHlfcHJlZCA8LSBpbnRlcmNlcHQgKyBzbG9wZSAqIERPUwogICAgICB5X2Rlcml2IDwtIHNsb3BlKihET1MgLSBUVEwpICsgKGludGVyY2VwdCArIHNsb3BlICogVFRMKQogICAgfQogICAgZGYgPC0gZGF0YS5mcmFtZSh4ID0gRE9TLCB5ID0geSwgeV9wcmVkID0geV9wcmVkLCB5X2Rlcml2ID0geV9kZXJpdikKICAgIAogICAgIyBHZXR0aW5nIHB2YWx1ZSBvZiB0aGUgbW9kZWwKICAgIHB2YWwgPC0gY3VydmUuY2xhc3NpZmljYXRpb25bY3VydmUuY2xhc3NpZmljYXRpb24kY3l0b2YgPT0gdGFyZ2V0X2ZlYXR1cmUsXSRwdmFsCiAgICAjIFBsb3QKICAgIHBsb3QgPC0gZ2dwbG90KGRmLCBhZXMoeCA9IHgsIHkgPSB5KSkgKwogICAgICBnZW9tX3BvaW50KGNvbG9yID0gImJsdWUiLCBhbHBoYSA9IDAuNSwgc2l6ZSA9IDEpICsKICAgICAgZ2VvbV9saW5lKGFlcyh5ID0geV9wcmVkKSwgY29sb3IgPSAicmVkIiwgc2l6ZSA9IDAuNykgKwogICAgICBnZW9tX2xpbmUoYWVzKHkgPSB5X2Rlcml2KSwgbGluZXR5cGUgPSAiZGFzaGVkIiwgY29sb3IgPSAicmVkIiwgc2l6ZSA9IDAuNykgKwogICAgICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSBUVEwsIGxpbmV0eXBlID0gImRhc2hlZCIsIGNvbG9yID0gInJlZCIsIHNpemUgPSAwLjcpICsKICAgICAgZ2d0aXRsZShwYXN0ZSh0YXJnZXRfZmVhdHVyZSwgcHZhbCwgc2VwPSIsXG5wID0gIikpICsKICAgICAgeGxhYihOVUxMKSArICAjIFJlbW92ZSB4LWF4aXMgbGFiZWwKICAgICAgeWxhYihOVUxMKSArICAjIFJlbW92ZSB5LWF4aXMgbGFiZWwKICAgICAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gNikpCiAgICAjIEFkZGluZyBwbG90IHRvIHRoZSBsaXN0IG9mIHBsb3RzCiAgICBwbG90c1tbcGFzdGUwKHRhcmdldF9mZWF0dXJlLCIuT09MIildXSA8LSBwbG90CiAgfQp9CgojIFNhdmluZyB0aGUgcGxvdHMKcGRmKHBhc3RlKGRydWdfYXNzYXlfcGF0aCwgIi9wbG90cy8iLCB0YXJnZXRfZHJ1ZywgIl9vbl8iLCBmZWF0dXJlX2Nob2ljZSwiLnBkZiIsIHNlcCA9ICIiKSkKZm9yIChqIGluIDE6Y2VpbGluZyhpLzE2KSl7CiAgZ3JpZC5hcnJhbmdlKGdyb2JzID0gcGxvdHNbKDE2KihqLTEpKzEpOm1pbigxNipqLGkpXSwgbnJvdyA9IDQsIG5jb2wgPSA0KQp9CmRldi5vZmYoKQpgYGAKCiMjIyBHbG9iYWwgdmlzdWFsaXphdGlvbiA6IGhlYXRtYXAKCmBgYHtyfQojIEZ1bmN0aW9uIHRvIHBsb3QgdGhlIHBoZWF0bWFwIG9mIHRoZSBmaW5hbCBkcnVnIGVmZmVjdApwbG90X3BoZWF0bWFwIDwtIGZ1bmN0aW9uKGRydWcubmFtZSwgZHJ1Zy5maW5hbC5lZmZlY3QuZGF0YWZyYW1lLCBjbHVzdGVyaW5nX3Jvd3MsIGNsdXN0ZXJpbmdfY29scywgZGVuZHJvPUZBTFNFKXsKICBteV9jb2xvcnMgPC0gYygiYmx1ZSIsIHJnYigwLCAwLCAxLCBhbHBoYSA9IDAuNSksICJ3aGl0ZSIsIHJnYigxLCAwLCAwLCBhbHBoYSA9IDAuNSksICJyZWQiKQogIAogICMgUHJlcGFyaW5nIHRoZSBkYXRhCiAgZGF0YSA8LSBhcy5tYXRyaXgoZHJ1Zy5maW5hbC5lZmZlY3QuZGF0YWZyYW1lWywgLTFdKQogIHJvd25hbWVzKGRhdGEpIDwtIGRydWcuZmluYWwuZWZmZWN0LmRhdGFmcmFtZSRwb3B1bGF0aW9uCiAgZGF0YVtpcy5uYShkYXRhKV0gPC0gMAogIAogICMgUmVvcmdhbml6aW5nIHJvd3MgYW5kIGNvbHVtbnMKICByb3dfb3JkZXIgPC0gb3JkZXIuZGVuZHJvZ3JhbShhcy5kZW5kcm9ncmFtKGNsdXN0ZXJpbmdfcm93cykpCiAgY29sX29yZGVyIDwtIG9yZGVyLmRlbmRyb2dyYW0oYXMuZGVuZHJvZ3JhbShjbHVzdGVyaW5nX2NvbHMpKQogIGRhdGEgPC0gZGF0YVtyb3dfb3JkZXIsIGNvbF9vcmRlcl0KICAKICAjIFBsb3QKICBwaGVhdG1hcChkYXRhLCAKICAgICAgICAgICBjb2xvciA9IG15X2NvbG9ycywKICAgICAgICAgICBuYV9jb2xvciA9ICJncmV5IiwKICAgICAgICAgICBjbHVzdGVyX3Jvd3MgPSBkZW5kcm8sIAogICAgICAgICAgIGNsdXN0ZXJfY29scyA9IGRlbmRybywKICAgICAgICAgICBtYWluID0gZHJ1Zy5uYW1lLAogICAgICAgICAgIGNlbGx3aWR0aCA9IDEwLCAKICAgICAgICAgICBjZWxsaGVpZ2h0ID0gMTAsCiAgICAgICAgICAgbGVnZW5kX2JyZWFrcyA9IGMoLTEsIC0wLjUsIDAsIDAuNSwgMSksCiAgICAgICAgICAgbGVnZW5kX2xhYmVscyA9IGMoIkRydWcgZWZmZWN0IGNvbGluZWFyXG50byBub3JtYWwgcHJlZ25hbmN5IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiTWlzc2luZyBWYWx1ZVxub3Jcbk5vdCBzaWduaWZpY2FudCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkRydWcgZWZmZWN0IG9wcG9zaXRlXG50byBub3JtYWwgcHJlZ25hbmN5IikKICAgICAgICAgICApCn0KYGBgCgpTYXZpbmcgdGhlIGhlYXQgbWFwcyBmb3IgYSBjaG9zZW4gc2V0IG9mIHRocmVzaG9sZHMuCgpgYGB7cn0KIyBQYXJhbWV0ZXJzIGZvciB0aGUgaGVhdCBtYXAgc2NvcmVzClRUTCA8LSAtODQKbm9ybWFsLmJlaGF2aW9yLnB2YWwudGhyZXNob2xkIDwtIDEuCm5vcm1hbC5iZWhhdmlvci5zbG9wZS50aHJlc2hvbGQgPC0gMC4KZHJ1Zy5wdmFsLnRocmVzaG9sZCA8LSAxLgpkcnVnLnNsb3BlLnRocmVzaG9sZCA8LSAwLgpmZWF0dXJlcy5vZi5pbnRlcmVzdCA8LSBuYW1lcyh0b3AuZmVhdHVyZS5pbmRleCkKcmVmLmNsdXN0ZXJpbmcuZmVhdHVyZSA8LSAiTWV0Zm9ybWluIgoKIyBCdWlsZGluZyB0aGUgY2x1c3RlcmluZyBvZiByZWZlcmVuY2UgZm9yIGFsbCB0aGUgaGVhdG1hcHMKcmVmX2RhdGEgPC0gY3JlYXRlLmRydWcuZWZmZWN0LmRhdGEuZnJhbWUoCiAgICAgICAgICAgICAgICAgIHJlZi5jbHVzdGVyaW5nLmZlYXR1cmUsCiAgICAgICAgICAgICAgICAgIG5vcm1hbC5iZWhhdmlvci5wdmFsLnRocmVzaG9sZCwgCiAgICAgICAgICAgICAgICAgIG5vcm1hbC5iZWhhdmlvci5zbG9wZS50aHJlc2hvbGQsIAogICAgICAgICAgICAgICAgICBkcnVnLnB2YWwudGhyZXNob2xkLCAKICAgICAgICAgICAgICAgICAgZHJ1Zy5zbG9wZS50aHJlc2hvbGQsCiAgICAgICAgICAgICAgICAgIFRUTCwKICAgICAgICAgICAgICAgICAgZmVhdHVyZXMub2YuaW50ZXJlc3QpCmRhdGEgPC0gYXMubWF0cml4KHJlZl9kYXRhWywgLTFdKQpyb3duYW1lcyhkYXRhKSA8LSByZWZfZGF0YSRwb3B1bGF0aW9uCmRhdGFbaXMubmEoZGF0YSldIDwtIDAKY2x1c3RlcmluZ19yb3dzIDwtIGhjbHVzdChkaXN0KGRhdGEpKQpjbHVzdGVyaW5nX2NvbHMgPC0gaGNsdXN0KGRpc3QodChkYXRhKSkpCgoKIyBQbG90dGluZyBhbGwgdGhlIGhlYXQgbWFwcwpwZGYocGFzdGUoZHJ1Z19hc3NheV9wYXRoLCAiL3Bsb3RzL0RydWcgZWZmZWN0IGhlYXRtYXBzIFRUTD0iLFRUTCwgIi5wZGYiLCBzZXA9IiIpLCB3aWR0aCA9IDEyLCBoZWlnaHQgPSA2KQpmb3IgKHRhcmdldF9kcnVnIGluIHVuaXF1ZShmaW5hbC5tb2RlbCRkcnVnKSl7CiAgcGxvdF9waGVhdG1hcCh0YXJnZXRfZHJ1ZywgCiAgICAgICAgICAgICAgICBjcmVhdGUuZHJ1Zy5lZmZlY3QuZGF0YS5mcmFtZSgKICAgICAgICAgICAgICAgICAgdGFyZ2V0X2RydWcsCiAgICAgICAgICAgICAgICAgIG5vcm1hbC5iZWhhdmlvci5wdmFsLnRocmVzaG9sZCwgCiAgICAgICAgICAgICAgICAgIG5vcm1hbC5iZWhhdmlvci5zbG9wZS50aHJlc2hvbGQsIAogICAgICAgICAgICAgICAgICBkcnVnLnB2YWwudGhyZXNob2xkLCAKICAgICAgICAgICAgICAgICAgZHJ1Zy5zbG9wZS50aHJlc2hvbGQsCiAgICAgICAgICAgICAgICAgIFRUTCwKICAgICAgICAgICAgICAgICAgZmVhdHVyZXMub2YuaW50ZXJlc3QpLAogICAgICAgICAgICAgICAgY2x1c3RlcmluZ19yb3dzLAogICAgICAgICAgICAgICAgY2x1c3RlcmluZ19jb2xzLAogICAgICAgICAgICAgICAgZGVuZHJvPUZBTFNFKQp9CmRldi5vZmYoKQpgYGAKCiMjIyBHbG9iYWwgdmlzdWFsaXphdGlvbiA6IGRydWcgZWZmZWN0cwoKSGVyZSB3ZSBwbG90IGEgZmlndXJlIGhlbHBpbmcgdXMgdmlzdWFsaXplIHRoZSBlZmZlY3Qgb2Ygb25lIGRydWcgYmFzZWQgb24gdGhlIHNsb3BlIG9mIGl0cyBsaW5lYXIgbW9kZWwgYWNyb3NzIGFsbCBmZWF0dXJlcy4KCmBgYHtyfQpzbG9wZV90aHJlc2hvbGQgPC0gMmUtMSAjIEFib3ZlIHRoaXMgdGhyZXNob2xkIHRoZSBjb2xvciBvZiB0aGUgcGxvdCB3aWxsIGJlIHRoZSBtb3N0IGludGVuc2Ugb25lCnB2YWxfdGhyZXNob2xkIDwtIDVlLTIgIyBVbmRlciB0aGlzIHRocmVzaG9sZCB0aGUgc2l6ZSBvZiB0aGUgbm9kZSB3aWxsIGJlIHRoZSBiaWdnZXN0IG9uZSAoaWYgdGFraW5nIHB2YWx1ZSBmb3Igc2l6ZSkKcm1zZV90aHJlc2hvbGQgPC0gMWUtMiAjIFVuZGVyIHRoaXMgdGhyZXNob2xkIHRoZSBzaXplIG9mIHRoZSBub2RlIHdpbGwgYmUgdGhlIGJpZ2dlc3Qgb25lIChpZiB0YWtpbmcgcm1zZSBmb3Igc2l6ZSkKcHJlY2lzaW9uIDwtIDAuICMgVW5kZXIgdGhpcyB0aHJlc2hvbGQgdGhlIHZhbHVlcyBpbiB0aGUgZGF0YXNldCBvbiB3aGljaCB0aGUgbW9kZWwgaXMgYnVpbHQgaXMgbm90IHJlbGV2YW50IChTbG9wZV9pbnRlbnNpdHkgPC0gMCkKCmZpbmFsLm1vZGVsLmluZm8uZGVjb21wIDwtIGZpbmFsLm1vZGVsICU+JQogICAgICAgICAgICAgICAgICAgICAgICBncm91cF9ieShmZWF0dXJlLCBkcnVnKSAlPiUKICAgICAgICAgICAgICAgICAgICAgICAgc2xpY2UoMSkgJT4lCiAgICAgICAgICAgICAgICAgICAgICAgIG11dGF0ZSgjIFJldHJpZXZpbmcgdGhlIHNlcGFyYXRpb24gOiBwb3B1bGF0aW9uLCByZWFnZW50LCBzdGltdWxhdGlvbgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcG9wdWxhdGlvbiA9IHN1YigiXiguKj8pXy4qIiwgIlxcMSIsIGFzLmNoYXJhY3RlcihmZWF0dXJlKSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZWFnZW50ID0gc3ViKCIuKj9fKC4qPylfLioiLCAiXFwxIiwgYXMuY2hhcmFjdGVyKGZlYXR1cmUpKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN0aW11bGF0aW9uID0gc3ViKCIuKl8uKl8oLiopIiwgIlxcMSIsIGFzLmNoYXJhY3RlcihmZWF0dXJlKSksCgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBJZiB0aGUgYWJzb2x1dGUgdmFsdWUgb2YgdGhlIHNsb3BlIGlzIGdyZWF0ZXIgdGhhbiB0aGUgdGhyZXNob2xkLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgdGhlIHNsb3BlIGlzIHJlcGxhY2VkIGJ5IHRoZSB0aHJlc2hvbGQgKHdpdGggdGhlIGFkZXF1YXRlIHNpZ24pCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBTbG9wZSA9IGlmZWxzZShzbG9wZSA+IHNsb3BlX3RocmVzaG9sZCwgc2xvcGVfdGhyZXNob2xkLCBzbG9wZSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBTbG9wZSA9IGlmZWxzZShzbG9wZSA8IC1zbG9wZV90aHJlc2hvbGQsIC1zbG9wZV90aHJlc2hvbGQsIHNsb3BlKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgSWYgdGhlIHB2YWx1ZSBpcyBzbWFsbGVyIHRoYW4gdGhlIHRocmVzaG9sZCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIHRoZSBwdmFsdWUgaXMgcmVwbGFjZWQgYnkgdGhlIHRocmVzaG9sZAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcHZhbCA9IGlmZWxzZShwdmFsIDwgcHZhbF90aHJlc2hvbGQsIHB2YWxfdGhyZXNob2xkLCBwdmFsKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgbG9nIHRyYW5zZm9ybSBub3JtYWxpemVkIGJ5IHRoZSB0aHJlc2hvbGQKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxvZ19wdmFsID0gbG9nMTAocHZhbCkvbG9nMTAocHZhbF90aHJlc2hvbGQpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBJZiB0aGUgcm1zZSBpcyBzbWFsbGVyIHRoYW4gdGhlIHRocmVzaG9sZCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIHRoZSBybXNlIGlzIHJlcGxhY2VkIGJ5IHRoZSB0aHJlc2hvbGQKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFJNU0UgPSBpZmVsc2Uocm1zZSA8IHJtc2VfdGhyZXNob2xkLCBybXNlX3RocmVzaG9sZCwgcm1zZSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIGxvZyB0cmFuc2Zvcm0gbm9ybWFsaXplZCBieSB0aGUgdGhyZXNob2xkCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsb2dfUk1TRSA9IGxvZzEwKFJNU0UpL2xvZzEwKHJtc2VfdGhyZXNob2xkKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgU2xvcGVfaW50ZW5zaXR5ID0gU2xvcGUvKG1heChzdWJzZXQgZGF0YSkgLSBtaW4oc3Vic2V0IGRhdGEpKSBvbmx5IHdoZW4gdGhlIG1lYXN1cmVzIGFyZSBzaWduaWZpY2FudAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWF4X3ZhbCA9IG1heChBbGxQZW5Eb3NlcmVzcG9uc2VbQWxsUGVuRG9zZXJlc3BvbnNlJGRydWcgPT0gZHJ1ZyAmIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBBbGxQZW5Eb3NlcmVzcG9uc2UkZmVhdHVyZSA9PSBmZWF0dXJlLF0kdmFsdWUpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWluX3ZhbCA9IG1pbihBbGxQZW5Eb3NlcmVzcG9uc2VbQWxsUGVuRG9zZXJlc3BvbnNlJGRydWcgPT0gZHJ1ZyAmIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBBbGxQZW5Eb3NlcmVzcG9uc2UkZmVhdHVyZSA9PSBmZWF0dXJlLF0kdmFsdWUpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgU2xvcGVfaW50ZW5zaXR5ID0gaWZlbHNlKG1heF92YWwgLSBtaW5fdmFsIDwgcHJlY2lzaW9uLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDAsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgU2xvcGUvKG1heF92YWwgLSBtaW5fdmFsKSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgQ29vcmRpbmF0ZXMgZm9yIHRoZSBwbG90IG9mIHRoZSByZWFnZW50cwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyMgU1RBVCBmaXJzdCBjb2x1bW4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHggPSBpZmVsc2UoZ3JlcGwoIlNUQVQiLCByZWFnZW50KSwgMS41LCAwKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMjIFNUQVQxICgxLDQpCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5ID0gaWZlbHNlKHJlYWdlbnQgPT0gIlNUQVQxIiwgNCwgMCksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIyBTVEFUMyAoMSwzKQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeSA9IGlmZWxzZShyZWFnZW50ID09ICJTVEFUMyIsIDMsIHkpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyMgU1RBVDUgKDEsMikKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHkgPSBpZmVsc2UocmVhZ2VudCA9PSAiU1RBVDUiLCAyLCB5KSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMjIFNUQVQ2ICgxLDEpCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5ID0gaWZlbHNlKHJlYWdlbnQgPT0gIlNUQVQ2IiwgMSwgeSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIyBORmtCICgzLDQpCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB4ID0gaWZlbHNlKHJlYWdlbnQgPT0gIk5Ga0IiLCAzLCB4KSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHkgPSBpZmVsc2UocmVhZ2VudCA9PSAiTkZrQiIsIDQsIHkpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyMgRVJLICgzLDMpCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB4ID0gaWZlbHNlKHJlYWdlbnQgPT0gIkVSSyIsIDMsIHgpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeSA9IGlmZWxzZShyZWFnZW50ID09ICJFUksiLCAzLCB5KSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMjIFM2ICgzLDIpCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB4ID0gaWZlbHNlKHJlYWdlbnQgPT0gIlM2IiwgMywgeCksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5ID0gaWZlbHNlKHJlYWdlbnQgPT0gIlM2IiwgMiwgeSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIyBNQVBLQVBLMiAoMywxKQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeCA9IGlmZWxzZShyZWFnZW50ID09ICJNQVBLQVBLMiIsIDMsIHgpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeSA9IGlmZWxzZShyZWFnZW50ID09ICJNQVBLQVBLMiIsIDEsIHkpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyMgSWtCICg0LDQpCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB4ID0gaWZlbHNlKHJlYWdlbnQgPT0gIklrQiIsIDQsIHgpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeSA9IGlmZWxzZShyZWFnZW50ID09ICJJa0IiLCA0LCB5KSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMjIENSRUIgKDQsMykKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHggPSBpZmVsc2UocmVhZ2VudCA9PSAiQ1JFQiIsIDQsIHgpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeSA9IGlmZWxzZShyZWFnZW50ID09ICJDUkVCIiwgMywgeSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIyBwMzggKDQsMikKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHggPSBpZmVsc2UocmVhZ2VudCA9PSAicDM4IiwgNCwgeCksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5ID0gaWZlbHNlKHJlYWdlbnQgPT0gInAzOCIsIDIsIHkpKQpgYGAKCkhlcmUgd2UgYXJlIGRvaW5nIG9uZSBvZiB0aGUgMTAwIHBsb3RzIHRoYXQgYXJlIGdvaW5nIHRvIGJlIGJ1aWx0IGZvciBlYWNoIGRydWcgc28gdGhhdCB3ZSBjYW4gcGxvdCB0aGUgbGVnZW5kIGFzIHdlbGwuIEVhY2ggbm9kZSByZXByZXNlbnQgYSByZWFnZW50LCBpdHMgc2l6ZSBpcyBwcm9wb3J0aW9uYWwgdG8gJC1sb2dfezEwfShwX3t2YWx9KSQsIGl0cyBjb2xvciBpcyAKCmBgYHtyfQojIEV4YW1wbGUgb2Ygc2V0dGluZ3MgZm9yIHRoZSBwbG90CmV4YW1wbGVfZHJ1ZyA8LSAiRm9saWMgYWNpZCIKZXhhbXBsZV9wb3B1bGF0aW9uIDwtICJDRDRUZW0iCmV4YW1wbGVfc3RpbXVsYXRpb24gPC0gIklGTmEiCgojIFN1YnNldApkZiA8LSBmaW5hbC5tb2RlbC5pbmZvLmRlY29tcFtmaW5hbC5tb2RlbC5pbmZvLmRlY29tcCRkcnVnID09IGV4YW1wbGVfZHJ1ZyAmIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpbmFsLm1vZGVsLmluZm8uZGVjb21wJHBvcHVsYXRpb24gPT0gZXhhbXBsZV9wb3B1bGF0aW9uICYKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmaW5hbC5tb2RlbC5pbmZvLmRlY29tcCRzdGltdWxhdGlvbiA9PSBleGFtcGxlX3N0aW11bGF0aW9uLF0KCiMgUGxvdApwIDwtIGdncGxvdChkZiwgYWVzKHggPSB4LCB5ID0geSkpICsKICAjIE5vZGVzIHNpemUsIGJvcmRlciBhbmQgY29sb3IKICBnZW9tX3BvaW50KGFlcyhzaXplID0gbG9nX3B2YWwsIGZpbGwgPSBTbG9wZV9pbnRlbnNpdHkpLCBzaGFwZSA9IDIxKSArCiAgIyBOYW1lIG9mIHRoZSBub2RlcwogIGdlb21fdGV4dChhZXMobGFiZWwgPSByZWFnZW50KSwgdmp1c3QgPSAtMS41LCBoanVzdCA9IDAuNSwgc2l6ZSA9IDUsIGNvbG9yID0gImJsYWNrIikgKwogICMgU2NhbGUgb2YgdGhlIHNpemUgb2YgdGhlIG5vZGVzCiAgc2NhbGVfc2l6ZV9jb250aW51b3VzKHJhbmdlID0gYygyLCAxMCksIGxpbWl0cyA9IGMoMCwgMSkpICsKICAjIFNjYWxlIG9mIHRoZSBjb2xvciBvZiB0aGUgbm9kZXMKICBzY2FsZV9maWxsX2dyYWRpZW50Mihsb3cgPSAiYmx1ZSIsIG1pZCA9ICJ3aGl0ZSIsIGhpZ2ggPSAicmVkIiwgbWlkcG9pbnQgPSAwLCBsaW1pdHMgPSBjKC0wLjMsIDAuMykpICsKICAjIExlZ2VuZCBzZXR0aW5ncyAocG9zaXRpb24gYW5kIGJhY2tncm91bmQpCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIsIGxlZ2VuZC5ib3ggPSAiaG9yaXpvbnRhbCIsIGxlZ2VuZC5rZXkgPSBlbGVtZW50X2JsYW5rKCkpICsKICAjIEF4aXMKICBzY2FsZV94X2NvbnRpbnVvdXMobGltaXRzID0gYygwLjUsIDUpLCBleHBhbmQgPSBjKDAsIDApKSArICAjIFNldCB4LWF4aXMgbGltaXRzIGFuZCByZW1vdmUgZXhwYW5zaW9uCiAgc2NhbGVfeV9jb250aW51b3VzKGxpbWl0cyA9IGMoMC41LCA0LjUpLCBleHBhbmQgPSBjKDAuLCAwLikpICsKICAjIExhYmxlcwogIGxhYnMoeCA9IE5VTEwsIHkgPSBOVUxMLCBzaXplID0gImxvZ19wdmFsIiwgZmlsbCA9ICJTbG9wZV9pbnRlbnNpdHkiLCBjb2xvciA9ICJDbGFzcyIpCgojIFNhdmluZyB0aGUgcGxvdApnZ3NhdmUocGFzdGUwKGRydWdfYXNzYXlfcGF0aCwgIi9wbG90cy9sZWdlbmRfZ3JpZF9lZmZlY3RfcGxvdC5wbmciKSwgcGxvdCA9IHAsIHdpZHRoID0gMTAsIGhlaWdodCA9IDgpCmBgYAoKUGxvdHRpbmcgYSBncmlkIGNvbXBvc2VkIG9mIHN1YnBsb3RzIGxpa2UgdGhlIG9uZSBhYm92ZSBmb3IgZXZlcnkgcG9wdWxhdGlvbiBhbmQgYXZlcnkgc3RpbXVsYXRpb24gYW5kIGVhY2ggZHJ1ZwoKYGBge3J9CiMgVXNlZnVsIHZhcmlhYmxlcyAod2UgcmV3cml0ZSB0aGVtIGJlY2F1c2UgdGhlIG9yZGVyIGlzIGltcG9ydGFudCBmb3IgdGhlIGZpZ3VyZXMpCnN0aW11bGF0aW9ucyA8LSBjKCJHTUNTRiIsICJJRk5hIiwgIklMMjQ2IiwgIkxQUyIsICJ1bnN0aW0iKQpwb3B1bGF0aW9ucyA8LSBjKCJCY2VsbHMiLCAiQ0Q0VGNtIiwgIkNENFRlZmYiLCAiQ0Q0VGVtIiwgIkNENFRuYWl2ZSIsICJDRDRuZWdDRDhuZWdUY2VsbHMiLCAiQ0Q1NmhpQ0QxNm5lZ05LIiwgIkNENTZsb0NEMTZwb3NOSyIsICJDRDhUY20iLCAiQ0Q4VGVmZiIsICJDRDhUZW0iLCAiQ0Q4VG5haXZlIiwgIkdyYW51bG9jeXRlcyIsICJNRFNDcyIsICJOS1QiLCAiVHJlZ3MiLCAiaW50TUNzIiwgIm1EQ3MiLCAibmNNQ3MiLCAicERDcyIpCkRydWdzIDwtIGMoIkNlZm90YXhpbWUiLCAiTGFuc29wcmF6b2xlIiwgIklvcGFtaWRvbCIsICJJb2hleG9sIiwgIkJlbnp5bHBlbmljaWxsaW4iLCAiQ2hsb3J0aGFsaWRvbmUiLCAiUmlmYWJ1dGluIiwgIklvZGl4YW5vbCIsICJNZXRmb3JtaW4iLCAiRm9saWMgYWNpZCIsICJDbG90cmltYXpvbGUiLCAiTWFwcm90aWxpbmUiLCAiUHJvZ2VzdGVyb25lIiwgIlByYXZhc3RhdGluIiwgIk1ldGh5bHByZWRvbmlzb2xvbmUiKQpmZWF0dXJlcy5vZi5pbnRlcmVzdCA8LSBuYW1lcyh0b3AuZmVhdHVyZS5pbmRleCkKICAKcGxvdF9kcnVnX2dyaWRfZWZmZWN0IDwtIGZ1bmN0aW9uKHRhcmdldF9kcnVnLCBmZWF0dXJlcy5vZi5pbnRlcmVzdCl7CiAgcGxvdF9saXN0IDwtIGxpc3QoKQogICMgSXRlcmF0ZSBvdmVyIHRoZSByb3dzIGFuZCBjb2x1bW5zIHRvIGNyZWF0ZSB0aGUgcGxvdHMKICBwb3BfdGl0bGUgPC0gVFJVRQogIGZvciAoc3RpbSBpbiBzdGltdWxhdGlvbnMpIHsKICAgIHN0aW1fdGl0bGUgPC0gVFJVRQogICAgZm9yIChwb3B1bGF0aW9uIGluIHBvcHVsYXRpb25zKSB7CiAgICAgICMgRmlsdGVyIHRoZSBkYXRhIGZvciB0aGUgY3VycmVudCBwb3B1bGF0aW9uIGFuZCBzdGltdWxhdGlvbgogICAgICBzdWJzZXRfZGYgPC0gZmluYWwubW9kZWwuaW5mby5kZWNvbXBbZmluYWwubW9kZWwuaW5mby5kZWNvbXAkZHJ1ZyA9PSB0YXJnZXRfZHJ1ZyAmCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpbmFsLm1vZGVsLmluZm8uZGVjb21wJHBvcHVsYXRpb24gPT0gcG9wdWxhdGlvbiAmCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpbmFsLm1vZGVsLmluZm8uZGVjb21wJHN0aW11bGF0aW9uPT1zdGltLF0gJT4lCiAgICAgICAgICAgICAgICAgICAgbXV0YXRlKG9mLmludGVyZXN0ID0gaWZlbHNlKGZlYXR1cmUgJWluJSBmZWF0dXJlcy5vZi5pbnRlcmVzdCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlllcyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJObyIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICBib3JkZXIudGhpY2tuZXNzID0gaWZlbHNlKGZlYXR1cmUgJWluJSBmZWF0dXJlcy5vZi5pbnRlcmVzdCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAyLiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAxLikpCiAgICAgIAogICAgICAjIFN1YnBsb3QgZm9yIHRoZSBjdXJyZW50IHBvcHVsYXRpb24gYW5kIHN0aW11bGF0aW9uCiAgICAgIHAgPC0gZ2dwbG90KHN1YnNldF9kZiwgYWVzKHggPSB4LzI1LCB5ID0geS8yNSwgY29sb3I9b2YuaW50ZXJlc3QsIHN0cm9rZT1ib3JkZXIudGhpY2tuZXNzKSkgKwogICAgICAgICMgTm9kZXMgc2l6ZSwgYm9yZGVyIGFuZCBjb2xvcgogICAgICAgIGdlb21fcG9pbnQoYWVzKHNpemUgPSBsb2dfcHZhbCwgZmlsbCA9IFNsb3BlX2ludGVuc2l0eSwgY29sb3I9b2YuaW50ZXJlc3QsIHN0cm9rZT1ib3JkZXIudGhpY2tuZXNzKSwgc2hhcGUgPSAyMSkgKwogICAgICAgICMgU2NhbGUgb2YgdGhlIHNpemUgb2YgdGhlIG5vZGVzCiAgICAgICAgc2NhbGVfc2l6ZV9jb250aW51b3VzKHJhbmdlID0gYygyLCAxMCksIGxpbWl0cyA9IGMoMCwgMSkpICsKICAgICAgICAjIFNjYWxlIG9mIHRoZSBjb2xvciBvZiB0aGUgbm9kZXMKICAgICAgICBzY2FsZV9maWxsX2dyYWRpZW50Mihsb3cgPSAiYmx1ZSIsIG1pZCA9ICJ3aGl0ZSIsIGhpZ2ggPSAicmVkIiwgbWlkcG9pbnQgPSAwLCBsaW1pdHMgPSBjKC0wLjMsIDAuMykpICsKICAgICAgICAjIEJvcmRlciBvZiB0aGUgbm9kZXMKICAgICAgICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gYygiWWVzIiA9ICJyZWQiKSkgKwogICAgICAgICMgQWRkaW5nIGEgYm9yZGVyIHRvIHRoZSBmaWd1cmUgaWYgdGhlcmUgYXJlIGZlYXR1cmVzIG9mIGludGVyZXN0IGluc2lkZQogICAgICAgIGdlb21fcmVjdChhZXMoeG1pbiA9IDAuMDIsIHhtYXggPSAwLjIsIHltaW4gPSAwLiwgeW1heCA9IDAuMiksCiAgICAgICAgICAgICAgICAgIGZpbGwgPSBOQSwKICAgICAgICAgICAgICAgICAgY29sb3IgPSAicmVkIiwKICAgICAgICAgICAgICAgICAgbGluZXR5cGUgPSAic29saWQiLAogICAgICAgICAgICAgICAgICBzaXplID0gaWZlbHNlKGFueShzdWJzZXRfZGYkb2YuaW50ZXJlc3QgPT0gIlllcyIpLCAxLjUsIE5BKSkgKwogICAgICAgICMgUmVtb3ZpbmcgbGVnZW5kcyBhbmQgYWRqdXN0aW5nIHNpemUgYW5kIG1hcmdpbnMKICAgICAgICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIsCiAgICAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSA2LCBtYXJnaW4gPSBtYXJnaW4ociA9IDApKSwKICAgICAgICAgIHBsb3QubWFyZ2luID0gbWFyZ2luKDAuNSwgMC4sIDAuLCAwLjUpLAogICAgICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgIGF4aXMudGlja3MueCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgIGF4aXMudGlja3MueSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfdGV4dChzaXplID0gNiwgbWFyZ2luID0gbWFyZ2luKHIgPSAtMikpLAogICAgICAgICAgYXhpcy50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSA2KSkgKyAgCiAgICAgICAgIyBMYWJlbHMgKHkgbGFiZWwgb25seSBhcHBlYXIgZm9yIHRoZSBmaXJzdCBjb2x1bW4gb2Ygc3VicGxvdCB3aXRoIHRoZSBuYW1lIG9mIHRoZSBzdGltKQogICAgICAgIGxhYnMoeCA9IE5VTEwsIHkgPSBpZmVsc2Uoc3RpbV90aXRsZSwgc3RpbSwgIiIpLCBzaXplID0gImxvZ19wdmFsIiwgZmlsbCA9ICJTbG9wZV9pbnRlbnNpdHkiLCBjb2xvciA9ICJDbGFzcyIpICsKICAgICAgICAjIEF4aXMKICAgICAgICBzY2FsZV94X2NvbnRpbnVvdXMobGltaXRzID0gYygwLjAyLCAwLjIpLCBleHBhbmQgPSBjKDAsIDApKSArCiAgICAgICAgc2NhbGVfeV9jb250aW51b3VzKGxpbWl0cyA9IGMoMC4sIDAuMiksIGV4cGFuZCA9IGMoMC4sIDAuKSkgKwogICAgICAgICMgVGl0bGUgKG9ubHkgYXBwZWFyIGZvciB0aGUgZmlyc3Qgcm93IG9mIHN1YnBsb3RzIHdpdGggdGhlIG5hbWUgb2YgdGhlIHBvcHVsYXRpb24pCiAgICAgICAgZ2d0aXRsZShpZmVsc2UocG9wX3RpdGxlLCBwb3B1bGF0aW9uLCAiIikpICsKICAgICAgICAjIFJlbW92aW5nCiAgICAgICAgZ3VpZGVzKGZpbGwgPSAibm9uZSIsIGNvbG9yID0gIm5vbmUiLCBzaXplID0gIm5vbmUiKQogICAgICAKICAgICAgIyBTdG9yZSB0aGUgcGxvdCBpbiB0aGUgcGxvdCBsaXN0CiAgICAgIHBsb3RfbGlzdFtbbGVuZ3RoKHBsb3RfbGlzdCkgKyAxXV0gPC0gcAogICAgICBzdGltX3RpdGxlIDwtIEZBTFNFCiAgICB9CiAgICBwb3BfdGl0bGUgPC0gRkFMU0UKICB9CiAgCiAgIyBDcmVhdGluZyB0aGUgZ3JpZCBwbG90CiAgZ3JpZF9hcnJhbmdlIDwtIGdyaWQuYXJyYW5nZShncm9icyA9IHBsb3RfbGlzdCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5jb2wgPSBsZW5ndGgocG9wdWxhdGlvbnMpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbnJvdyA9IGxlbmd0aChzdGltdWxhdGlvbnMpKQogICMgQWRkaW5nIGEgdGl0bGUgdG8gdGhlIGdyaWQgcGxvdAogIHRpdGxlIDwtIHRleHRHcm9iKHRhcmdldF9kcnVnLCBncCA9IGdwYXIoZm9udHNpemUgPSAxNiwgZm9udGZhY2UgPSAiYm9sZCIpKQogIGxheW91dCA8LSByYmluZChjKDEpLCBjKDIpKQogIGFycmFuZ2VkX3Bsb3RzIDwtIGFycmFuZ2VHcm9iKHRpdGxlLCBncmlkX2FycmFuZ2UsIGxheW91dF9tYXRyaXggPSBsYXlvdXQsIGhlaWdodHMgPSBjKDEsIDkpKQogIAogIHJldHVybihhcnJhbmdlZF9wbG90cykKfQoKIyBDcmVhdGluZyBhbmQgc2F2aW5nIHRoZSBmaWd1cmVzIGluIHBkZiBmaWxlcwpmb3IgKHRhcmdldF9kcnVnIGluIERydWdzKSB7CiAgZ3JpZF9wbG90IDwtIHBsb3RfZHJ1Z19ncmlkX2VmZmVjdCh0YXJnZXRfZHJ1ZywgZmVhdHVyZXMub2YuaW50ZXJlc3QpCiAgcGRmKHBhc3RlKGRydWdfYXNzYXlfcGF0aCwgIi9wbG90cy8iLCB0YXJnZXRfZHJ1ZywgIl9ncmlkX2VmZmVjdF9wbG90cy5wZGYiLCBzZXA9IiIpLCB3aWR0aD0yMCwgaGVpZ2h0PTgpCiAgZ3JpZC5kcmF3KGdyaWRfcGxvdCkKICBkZXYub2ZmKCkKfQpgYGAKCgoKCg==